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

发布于 2025-01-02 05:37:16 字数 942 浏览 2 评论 0原文

我有一个通用类型 Store 并使用 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 方法?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

没有你我更好 2025-01-09 05:37:16

由于实际类型 T 只能通过反射来使用,因此您还需要通过反射访问 Store 的方法:

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 将保持通用,但你可以访问它的CountItems 通过转换为 IStore

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

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);
无人问我粥可暖 2025-01-09 05:37:16

就不能包起来吗?

类似的事情

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]

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]
我不在是我 2025-01-09 05:37:16

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

您可以尝试引入一个接口IStorage并尝试使其协变或逆变(您见过这个选项吗?)。如果这不是一个选项,例如,如果您在 Storage 中同时使用了输入和输出泛型类型,那么就无法实现您想要的功能。原因是由于这种情况,Storage 无法安全地用作 Storage

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

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));
风向决定发型 2025-01-09 05:37:16

T 必须是 Store类型避免使用 typeof(Store;

T must be the type Store<X> avoiding the use of typeof(Store<T>

但可醉心 2025-01-09 05:37:16

假设 someObjectThatImplementsIStorable 的类型为 MyStorable。

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

那么 x 不能转换为 Store,但可以转换为 Store。以下内容将起作用: (Store)x

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

u。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文