Initializing a Generic variable from a C# Type Variable

C#Generics

C# Problem Overview


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.

C# Solutions


Solution 1 - C#

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.

Solution 2 - C#

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);

Solution 3 - C#

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeter LangeView Question on Stackoverflow
Solution 1 - C#jasonView Answer on Stackoverflow
Solution 2 - C#cuongleView Answer on Stackoverflow
Solution 3 - C#SCBView Answer on Stackoverflow