Click here to Skip to main content
15,886,840 members
Please Sign up or sign in to vote.
3.50/5 (2 votes)
How do I reuse code in the following functions to return objects of different types?

C#
public A Execute(object parameters)
{
    using (var x = X.Create(parameters))
    {
        Process(x);
        return Func1(x);
    }
}

public B Execute(object parameters)
{
    using (var x = X.Create(parameters))
    {
        Process(x);
        return Func2(x);
    }
}


Func1 and Func2 are two different functions with different return types. I feel like some adaptation of the strategy pattern can be used here but I'm not sure what.
Posted
Updated 10-May-15 13:33pm
v2
Comments
PIEBALDconsult 10-May-15 20:15pm    
You can't do that. You need to sit back and think more clearly about what you really want.
BillWoodruff 11-May-15 1:32am    
For this idea to work (compile) based on your code example, both Funcs, the Process method, and the Class X and its 'Create method, would have to be static, and the Class X would have to implement IDisposable.

I suggest you add to your question a description of what you are dealing with that requires a Factory class that can return a new 'A or 'B.

There are examples of how to create a Factory Class implementation in C# here on CodeProject, and, of course, on the net.
BillWoodruff 11-May-15 9:17am    
I've posted an example of a working FactoryClass; see if that is helpful; if it's not helpful, let me know, and I'll remove it.

You can't have methods in the same class that only differ by their return type.

I can think of two ways for code-reuse here, both requiring making Execute(..) a generic method.

1) If you can replace Func1 and Func2 by a generic Func<T> :
C#
public T Execute<T>(object parameters)
{
    using (var x = X.Create(parameters))
    {
        Process(x);
        return Func<T>(x);
    }
}


2) If not, pass Func1 or Func2 as a delegate:
C#
// "..." stands for the static type name of the "x" below:
public T Execute<T>(object parameters, Func<..., T> func) 
{
    using (var x = X.Create(parameters))
    {
        Process(x);
        return func(x);
    }
}


Edit:
If your intention is to create a factory-method that returns either an object of type A or B, depending on the value of parameters, and A and B derive from a common base class (I'll call it A0 here) then something like this would be alright:
C#
public A0 Execute(object parameters)
{
    using (var x = X.Create(parameters))
    {
        Process(x);

        if (parameters == indicate_you_want_A)
            return Func1(x);
        else if (parameters == indicate_you_want_B)
            return Func2(x);
        else
            throw new NotSupportedException("meaningful message here");
    }
}
 
Share this answer
 
v3
Comments
Sergey Alexandrovich Kryukov 10-May-15 21:07pm    
Sure, a 5.
—SA
Sascha Lefèvre 11-May-15 7:29am    
Thank you, Sergey.
BillWoodruff 11-May-15 1:34am    
This is good medicine, Sascha, but I suspect the OP here has a more serious problem. See my comment on the OP.
Sascha Lefèvre 11-May-15 6:37am    
Good idea, Bill, I added it to the solution. Thank you.
Sri Prasad Tadimalla 11-May-15 3:25am    
Thanks everyone. I thought of passing the function in but I usually try to avoid doing that. The generic approach also seems like a good idea, especially if I make T an interface.
Here's an example of a static generic Class that will return instances of new Classes where the internal data type used by the new Class is constrained to be a struct. I believe this example demonstrates the "usual" features of implementing the Factory Class pattern in C#: use of an interface; generic constraints, etc.
C#
using System;

namespace StructClassFactoryDemo
{
    // see Note #1
    internal interface IGenericStruct<T> where T : struct
    {
        T[] Parameters { set; get; }

        void Execute(Func<T,T> paramFunc, T[] parameters);
    }

    internal static class GenericStructFactory<T> where T : struct
    {
        internal static GenericStructClass<T> Create(Func<T,T> paramFunc, params T[] parameters)
        {
            GenericStructClass<T> newT = new GenericStructClass<T>();

            if (paramFunc != null) newT.Execute(paramFunc, parameters);

            Console.WriteLine("created {0} type",  typeof(T).Name);

            return newT;
        }
    }

    public class GenericStructClass<T> : IGenericStruct<T> where T : struct
    {
        public T[] Parameters { set; get; }

        public void Execute(Func<T,T> paramFunc, T[] parameters)
        {
            if (parameters == null) return;

            // see Note #2
            if (typeof(T).IsValueType && paramFunc != null)
            {
                for (int i = 0; i < parameters.Length; i++)
                {
                    parameters[i] = paramFunc(parameters[i]);
                }
            }

            Parameters = parameters;
        }
    }
}
Here's how you might use this Factory in some Class:
C#
// predefined integer function
Func<int,int> intFunc = (x) =>
{
    return x + 100;
};

// predefined double function
Func<double, double> doubleFunc = (x) =>
{
    return x + 43.024;
};

// function parameter defined as 'null
GenericStructClass<int> ClassA0 = GenericStructFactory<int>
    .Create(
    null,
    new int[] { 1, 2, 3, 4, 5, 6 });

// using predefined integer function
GenericStructClass<int> ClassA1 = GenericStructFactory<int>
    .Create(
    intFunc,
    new int[] { 1, 2, 3, 4, 5, 6 });

// using predefined double function
GenericStructClass<double> ClassA2 = GenericStructFactory<double>
    .Create(
    doubleFunc,
    new double[] { 1.24, 2.23, 3.5, 4.9, 5.1, 6.2 });

// using an in-line lambda expression that returns a 'long for the function
GenericStructClass<long> ClassA3 = GenericStructFactory<long>
    .Create(
    x => x + 23,
    new long[] { 1, 2, 3, 4, 5, 6 });

// using an in-line lambda expression that returns a 'DateTime for the function
GenericStructClass<DateTime> ClassA4 = GenericStructFactory<DateTime>
    .Create(
    dt => dt.AddDays(100),
    new DateTime[]
    {
        DateTime.Now, DateTime.Now.AddDays(1), DateTime.Now.AddDays(2)
    });
Notes:

1. even though an Interface is implemented here, the code shown really does not demonstrate its use in a specific way; so, why's it there ? : imho, it is often the case that you will want to extend a Factory class, and you would use the Interface shown to define another Class that would be used as an alternative to 'GenericStructClass. Further, imho, it is a good idea to use Interfaces to "enforce discipline" in development.

2. Note that you can't use 'ValueType as a constraint in a Generic Class, but you can use 'Struct, and, within a Generic Class, you can test to see if the Generic Type is a 'ValueType, as shown here.
 
Share this answer
 
v6
Comments
Sascha Lefèvre 11-May-15 11:50am    
Hi Bill,

I'm not much into factory patterns, so I might not be the most competent person to give you feedback on the 'factory-aspect' of this. However, here are my thoughts:

I don't see why this has to be constrained to structs - you could just remove the constraints (and the IsValueType-check) and it will still work. Since the inquirer didn't tell if he's dealing with value- or reference-types, removing (or commenting) the constraints might make sense.

When leaving the struct-constraint in, I don't see the purpose of the IsValueType-check. It will return true for all structs, and non-structs are ruled out by the generic constraint.

While I realize that this is just an example, the name of the interface IGenericStruct is a bit misleading and threw me off for a moment ;)

The c'tor of GenericStructClass could call Execute(..). Did you have a specific reason to not do this?

Currently, (as far as I can see) there's no real reason to implement it with a factory: If I implement a c'tor for GenericStructClass with the same arguments as Execute(..) then I can just create a new instance with 'new GenericStructClass<T>(..)' with the same effect. IMO there should either be a discriminating argument to the factory method for choosing this or the other specific implementation of some GenericStructClass to be created or the factory-class should be non-static so that it can be instantiated and passed somewhere where 'some' factory is required.

I don't know if your solution is what the inquirer was looking for - but since his question wasn't very specific to begin with I think it's a valid attempt to give him ideas and IMO you wouldn't need to delete it even if he responds to you that it's not what he had in mind.

/Sascha

PS: +5
Maciej Los 11-May-15 17:25pm    
5ed!
Sri Prasad Tadimalla 11-May-15 20:37pm    
Thanks! I have never used structs before but I have defined classes and static functions with generic constrained parameters.
I've generally usually used a static GetInstance function in a base class to instantiate derived types. What purpose does a separate factory class serve other than being needed if there is no base class (only an interface)?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900