47

我有一个泛型类型Store<T>并用于Activator制作这种类型的实例。现在,在使用 Activator 之后,如何将结果类型的对象object转换回实例化类型?我知道我用来实例化泛型的类型。请看以下代码:

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

我想做的是这样的:

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

但由于明显的原因,这不起作用。作为替代方案,我尝试了:

var store = (Store<IStorable>)x;

在我看来,这可能会起作用,但会给出InvalidCastException.

如何再次访问Store<T>我知道对象中的方法x

4

5 回答 5

35

由于T您只能通过反射获得实际类型,因此您还需要Store<T>通过反射访问方法:

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

编辑IStore您还可以定义一个不使用泛型的附加接口,IStorable而是使用:

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

Store<T>将保持通用,但您可以CountItems通过转换为IStore

var x = (IStore)Activator.CreateInstance(constructedType, new object[] { someParameter });
var count = x.CountItems((IStorable)someObjectThatImplementsStorable);
于 2012-02-04T12:44:45.997 回答
7

你不能把它包起来吗?

就像是

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

还是我错过了你想要做的事情?

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
{ }

印刷

1 
ConsoleApp1.Store'1[ConsoleApp1.Beer]
于 2012-02-04T12:42:19.977 回答
3

我认为最合适的答案是“你不能这样做”。

您可能会尝试引入一个接口IStorage并尝试使其成为协变或逆变的(您是否看到过该选项?)。如果它不是一个选项,例如,如果您在 中同时使用了输入和输出泛型类型Storage,那么就无法实现您想要的。原因是由于这种情况Storage<Beer>无法安全使用:Storage<IStorable>

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

如我所见,唯一可能的解决方法是从该方法中移出投射并将对象投射到您知道所有确切类型的位置:

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));
于 2012-02-04T12:49:58.150 回答
1

T 必须是 Store<X> 类型,避免使用 typeof(Store<T>

于 2013-12-06T13:37:19.447 回答
0

假设 someObjectThatImplementsIStorable 是 MyStorable 类型。

例如 MyStorable someObjectThatImplementsIStorable = new MyStorable( ); ... // 你的其余代码在这里。

那么 x 不能被强制转换为 Store,但它可以被强制转换为 Store。以下将起作用:(存储)x

注意,虽然 MyStorable 实现了 IStorable,但 Store 和 Store 之间没有关系。这是两个不同的类,它们不是相互派生的。

你。

于 2012-02-04T12:53:55.763 回答