75

I have a class that takes a Generic Type as part of its initialization.

public class AnimalContext<T>
{
    public DoAnimalStuff()
    {
        //AnimalType Specific Code
    }
}

What I can do right now is

AnimalContext<Donkey> donkeyContext = new AnimalContext<Donkey>();
AnimalContext<Orca> orcaContext = new AnimalContext<Orca>();

But what I need/want to do is be able to declare an AnimalContext initialized to a type that is only known at runtime. For instance,

Animal a = MyFavoriteAnimal(); //returns an instance of a class 
                               //implementing an animal
AnimalContext<a.GetType()> a_Context = new AnimalContext<a.GetType()>();
a_Context.DoAnimalStuff();

Is this even possible? I can't seem to find an answer for this online.

Peter Lange
  • 2,786
  • 2
  • 26
  • 40

3 Answers3

74

What you mean by this part is possible:

new AnimalContext<a.GetType()>();

Obviously that exact syntax is wrong, and we'll get to that, but it is possible to construct an instance of a generic type at runtime when you don't know the type parameters until runtime.

What you mean by this part is not:

AnimalContext<a.GetType()> a_Context

That is, it is impossible to type a variable as a generic type if you don't know the type parameters at compile-time. Generics are compile-time constructs, and rely on having the type information available at compile-time. Given this, you lose all the benefits of generics if you don't know the types at compile-time.

Now, to construct an instance of a generic type at runtime when you don't know the type until runtime, you can say:

var type = typeof(AnimalContext<>).MakeGenericType(a.GetType());
var a_Context = Activator.CreateInstance(type);   

Note that the compile-time type of a_context is object. You will have to cast a_context to a type or interface that defines the methods you need to access. Often what you'll see people do here is have the generic type AnimalContext<T> implement some interface (say IAnimalContext) or inherit from a non-generic base class (say AnimalContext) that defines the methods they need (so then you can cast a_context to the interface or the non-generic base class). Another alternative is to use dynamic. But again, keep in mind, you have none of the benefits of generic types in doing this.

jason
  • 236,483
  • 35
  • 423
  • 525
  • 5
    Everyone who answered gave an answer that provided a bit more information than the previous answer. All were correct, and excellent in quality, but only one can be selected as The Answer, so I chose this one which was the most descriptive. I would like to thank everyone who answered though, and I appreciate all the assistance (specially late on a Sunday night.) – Peter Lange Jul 08 '13 at 05:25
  • 1
    What if my Class is not generic but the inside Method is, How will i use the MakeGenericType in that case – N.K Jun 02 '17 at 06:09
  • 1
    By far the most useful answer ever about c# generics. After hours of research this saved so much time. Thank you so much – KingNDj Feb 25 '19 at 14:09
13

You can use reflection with generic type by using MakeGenericType method and take adavantage of dynamic keyword:

var type = typeof (AnimalContext<>).MakeGenericType(a.GetType());
dynamic a_Context = Activator.CreateInstance(type);

So you can call:

a_Context.DoAnimalStuff();

Or use reflection again to call method:

type.GetMethod("DoAnimalStuff").Invoke(a_Context, null);
cuongle
  • 74,024
  • 28
  • 151
  • 206
6

You would need to create the type using Reflection and then invoke that type. Something like:

Animal a = MyFavoriteAnimal();
var contextType = typeof(EsbRepository<>).MakeGenericType(a.GetType());

dynamic context = Activator.CreateInstance(contextType);
context.DoAnimalStuff();

The use of dynamic means that the context variable will be evaluated at run time allowing for you to call the DoAnimalStuff method.

SCB
  • 3,034
  • 2
  • 25
  • 24