如何使用Activator创建泛型类型的实例并将其强制转换回该类型

本文关键字:转换 类型 Activator 何使用 创建 泛型类型 实例 | 更新日期: 2023-09-27 18:22: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

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

如何使用Activator创建泛型类型的实例并将其强制转换回该类型

由于实际类型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});

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

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

您的Store<T>将保持通用,但您可以通过转换为IStore:来访问其CountItems

var x = (IStore)Activator.CreateInstance(constructedType, new object[] { someParameter });
var count = x.CountItems((IStorable)someObjectThatImplementsStorable);

你能把它包起来吗?

类似的东西

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]

在我看来,最合适的答案是"你不能这样做"。

您可以尝试引入一个接口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));

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

假设someObjectThatImplementsIStorable属于MyStorable类型。

例如。MyStorable someObjectThatImplementsIStorable=新的MyStorable();…//此处显示您的其余代码。

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

请注意,尽管MyStorable实现了IStorable,但Store和Store之间没有关系。这是两个互不派生的不同类。

u。