Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing a Generic variable from a C# Type Variable

Tags:

c#

generics

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.

like image 568
Peter Lange Avatar asked Jul 08 '13 04:07

Peter Lange


3 Answers

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.

like image 105
jason Avatar answered Oct 19 '22 18:10

jason


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);
like image 13
cuongle Avatar answered Oct 19 '22 19:10

cuongle


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.

like image 6
SCB Avatar answered Oct 19 '22 19:10

SCB