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

人盡茶涼 提交于 2019-11-27 07:47:16

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

Cant you just wrap it?

something like

public Store<T> IConstructStore<T>(T item) where T : IStorable 
{
 return Activator.CreateInstance(typeof(Store<T>), new object[] { someParameter }) as Store<T>;
}

or am i missing what you are trying to do?

IE

class Program
{
    static void Main(string[] args)
    {
        Beer b = new Beer();
        var beerStore = IConstructStore(b);
        Console.WriteLine(beerStore.test);
        Console.WriteLine(beerStore.GetType().ToString());
    }

    public static Store<T> IConstructStore<T>(T item) where T : IStorable
    {
        return Activator.CreateInstance(typeof(Store<T>), new object[] { }) as Store<T>;
    }
}

interface IStorable { }

class Store<T> where T : IStorable
{
    public int test = 1;
}

class Beer : IStorable
{ }

prints

1 
ConsoleApp1.Store'1[ConsoleApp1.Beer]

Most appropriate answer in my opinion would be 'you can't do it in this way'.

You might try introducing an interface IStorage and try making it covariant or contravariant (have you seen that option?). If it is not an option, for example if you have both input and output generic types used in Storage, then there is no way to implement what you want. The reason is that Storage<Beer> cannot be safely used as Storage<IStorable> due to this case:

Storage<IStorable> store = new Storage<Beer>(); // let's pretend we can do it 
store.Save(new StorableButNotBeer()); // what will happen here?

The only possible workaround for you as I see is to move casting out from this method and cast the object in the place where you know all the exact types:

public void object CreateStore(Type istorableType)
{
    // here is your activator code, but you will have to return an object
}

var beerStore = (Store<Beer>)CreateStore(typeof(Beer));

T must be the type Store avoiding the use of typeof(Store

Let's say that someObjectThatImplementsIStorable is of type MyStorable.

e.g. MyStorable someObjectThatImplementsIStorable = new MyStorable( ); ... // rest of your code here.

Then x cannot be cast to Store, but it can be cast to Store. The following will work: (Store)x

Note that although MyStorable implements IStorable, there is no relationship between Store and Store. These are two distinct classes that do not derive from each other.

u.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!