我有一个泛型类型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
方法?
答案 0 :(得分:30)
由于只有通过反射才能使用实际类型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);
答案 1 :(得分:4)
你能不能把它包起来?
类似
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]
答案 2 :(得分: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));
答案 3 :(得分:0)
假设someObjectThatImplementsIStorable属于MyStorable类型。
e.g。 MyStorable someObjectThatImplementsIStorable = new MyStorable(); ... //这里的其余代码。
然后x不能转换为Store,但可以转换为Store。以下将起作用:(存储)x
请注意,尽管MyStorable实现了IStorable,但Store和Store之间没有任何关系。这是两个不相互派生的不同类。
Ú
答案 4 :(得分:0)
T必须是类型Store,避免使用typeof(Store