Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Activator to create an instance of a generic Type and casting it back to that type?

I have a generic type Store<T> and use Activator to make an instance of this type. Now how, after using the Activator, can I cast the resulted object of type object back to the instantiated type? I know the type that I used to instantiate the generic. Please see the following code:

class Store<T> where T : IStorable  {}  class Beer : IStorable  {}  class BeerStore : Store<Beer> {}  Type storeType = someObjectThatImplementsIStorable.GetType(); Type classType = typeof(Store<>); Type[] typeParams = new Type[] { storeType };    Type constructedType = classType.MakeGenericType(typeParams);  object x = Activator.CreateInstance(constructedType, new object[] { someParameter }); 

What I would like to do is something like this:

var store = (Store<typeof(objectThatImplementsIStorable)>)x; 

but that doesn't work for obvious reasons. As an alternative I tried:

var store = (Store<IStorable>)x; 

which could possibly work in my opinion, but gives an InvalidCastException.

How do I get access again to the Store<T> methods that I know are in the object x?

like image 287
Bazzz Avatar asked Feb 04 '12 12:02

Bazzz


People also ask

Can generic class instance be created?

Yes, this is nice especially if the generic class is abstract, you can do this in the concrete subclasses :) @TimKuipers The <E> in class Foo<E> is not bound to any particular type.

What is activator CreateInstance?

The Activator. CreateInstance method creates an instance of a type defined in an assembly by invoking the constructor that best matches the specified arguments. If no arguments are specified then the constructor that takes no parameters, that is, the default constructor, is invoked.


1 Answers

Since the actual type T is available to you only through reflection, you would need to access methods of Store<T> through reflection as well:

Type constructedType = classType.MakeGenericType(typeParams);  object x = Activator.CreateInstance(constructedType, new object[] { someParameter }); var method = constructedType.GetMethod("MyMethodTakingT"); var res = method.Invoke(x, new object[] {someObjectThatImplementsStorable}); 

EDIT You could also define an additional IStore interface that does not use generics, and uses IStorable instead:

interface IStore {     int CountItems(IStorable item); } class Store<T> : IStore where T : IStorable {     int CountItems(IStorable item) {         return count;     } } 

Your Store<T> would remain generic, but you would get access to its CountItems by casting to IStore:

var x = (IStore)Activator.CreateInstance(constructedType, new object[] { someParameter }); var count = x.CountItems((IStorable)someObjectThatImplementsStorable); 
like image 120
Sergey Kalinichenko Avatar answered Sep 18 '22 09:09

Sergey Kalinichenko