Search code examples
c#genericsreflectionactivator

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?


Solution

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