Search code examples
c#genericsinheritancefactorycovariant

C# Factory for generic inheritance


I apologize for this rather fundamental question, however, I could find no documentation. Perhaps because I do not know the proper terminology.

Class structure:

class D{}

abstract class A<T>{}
class B<T> : A<T> {}
class C : B<D> {}

I attempt to create a factory method returning C, while the overall return type must be A. Unfortunately this implementation will produce a compiletime error, altough the inheritance structure seems to be consummately covariant.

public A<T> FactoryMethod()
{
   return new C();
}

More specifically, I am trying to implement a factory, able to produce all three classes based on a input value, while the generic capability has to be obtained.

public A<T> FactoryMethod(int i, Type K)
{
   if(i == 1)
      return new A<K>():

   if(i == 2)
      return new B<K>():

   if(i == 3)
      return new C():
}

Update

I have to create three objects as follows.

A<string> first = FactoryMethod(1, string);
A<int> second = FactoryMethod(2, int);
A<int> third = FactoryMethod(3, int);

Solution

  • C is a sub class of the bound type A<D>. So the following is valid:

    public A<D> FactoryMethod()
    {
       return new C();
    }
    

    since we can safely say that C is a A<D>. However C is not a generic type and cannot be converted to the open type A<T> where T is a generic argument since T could be any type.

    However the following is valid:

    public A<T> FactoryMethod()
    {
       return new B<T>();
    }
    

    Since B<T> is an open generic type as well and any B<T> is an A<T>.


    Based on your update, you could write your factory method as:

    public A<T> FactoryMethod<T>(int i)
    {
       if(i == 1)
          return new A<T>():
       if(i == 2)
          return new B<T>():
       if(i == 3) 
          return (A<T>)(object)new C():
          // The cast to object gets rid of compile time checking,
          // but will throw an InvalidCastExceptoin if T is not D
    }
    

    This is a bit ugly with that weird hack for case 3. Then you would call it as:

    A<string> first = FactoryMethod<string>(1);
    A<int> second = FactoryMethod<int>(2);
    A<int> third = FactoryMethod<int>(3); // InvalidCastException!