Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# generic factory method

Perhaps this is a simple newbie C# question, but so be it---it will be a fresh break from my other questions, which are so difficult that no one knows the answer to them. :)

Let's say I have a generic type in C#:

Thing<T>

And let's say I want to make a thing using a static factory method. In Java, this is no problem:

public static <T> Thing<T> createThing()
{
  return flag ? new Thing<Integer>(5) : new Thing<String>("hello");
}

How do I do this in C#? Thanks.

like image 878
Garret Wilson Avatar asked Feb 26 '23 05:02

Garret Wilson


2 Answers

If you want to return an instance of a templated class using one of many different template arguments, one way to do it is with an abstract base (or an interface):

abstract class UntypedThing { }
class Thing<T> : UntypedThing
{
    public Thing(T t) { }
}

class Foo
{
    public static UntypedThing createThing(bool flag)
    {
        if (flag)
            return new Thing<int>(5);
        else return new Thing<String>("hello");
    }
}

The UntypedThing class would contain as much code as possible that does not rely on the template type. The Thing class would ideally only contain code that relies on the template type. The factory class Foo always returns the former.

like image 80
Reinderien Avatar answered Feb 28 '23 20:02

Reinderien


You can in theory use reflection to build up the correct generic type, but it will be pretty useless to you as at some point you will need to upcast it to a less specific type.

public class ThingFactory  {
    public object Create(bool flag) {
        Type outputType = null;
        if(flag) {
            outputType = typeof(string);
        } else {
            outputType = typeof(int);
        }
        return Activator.CreateInstance(typeof(Thing<>).MakeGenericType(outputType));
    }
}

As you can see, the value of doing this is about zero as you will need to cast the return type to the type you want, meaning that the logic to determine it needs to live outside the Create method.

I would use Reinderien's method and have a non-generic base. This is the most sane and idiomatic approach.

like image 33
Igor Zevaka Avatar answered Feb 28 '23 20:02

Igor Zevaka