C#如何使用“Type”类型的对象初始化泛型类

6
我最近遇到了这个问题。
doSomething(typeof(int));
doSomething(typeof(MyClassA));
doSomething(typeof(MyClassB));

public void doSomething(Type _type)
{
    var myGenObj = new MyGenericClass<_type>();  // Error.  Really I'd want MyGenericClass<int>, MyGenericClass<MyClassA>, etc depending on what's passed in.
    myGenObj.doSomeGenStuff();
    // more stuff...

}

我认为可以通过反射来实现这个功能。可能有更简单的方法。我对Type和Classes在底层的工作方式有些困惑。无论如何,感谢任何帮助。
谢谢。
2个回答

12
你想使用Type.MakeGenericTypeActivator.CreateInstance... 但是在新创建的对象上调用方法将很棘手。理想情况下,你可以有一个包含那些成员的非泛型基类或接口:
public interface IFoo
{
    void CallSomeMethod();
}

public class MyGenericClass<T> : IFoo
{
    ...
}

// Names changed to be more conventional
public void DoSomething(Type type)
{
    var genericType = typeof(MyGenericClass<>).MakeGenericType(type);
    var instance = (IFoo) Activator.CreateInstance(genericType);
    instance.CallSomeMethod();
}

如果您确实需要调用依赖于类型参数的方法,则需要使用反射或者动态语言(dynamic),这可以简化基于反射的代码。

编辑:正如cdhowie所说,如果您始终在编译时确切地知道类型,则可以使用泛型方法,这将使事情变得更加简单。然后您将像这样调用该方法:

DoSomething<int>();
DoSomething<MyClassA>();
DoSomething<MyClassB>();

谢谢,我以为会有更好的解决方案,但似乎没有。 - RayLoveless
@RayL:不,泛型在反射中很棘手 - 它们基本上是为编译时已知类型参数而设计的。 - Jon Skeet
@RayL:也请阅读cdhowie的回答——你提供的所有示例都是在编译时已知类型参数的情况下。这是否属实?如果是,请使用泛型方法。 - Jon Skeet

5

像这样:

object myGenObj = Activator.CreateInstance(typeof(MyGenericClass<>).MakeGenericType(_type));

然而,由于生成的对象在编译时是未知类型的,您无法通过通用类型(除非通过反射)真正调用对象成员。 如果在编译时存在一个祖先类型或实现的接口,您可以将其强制转换为该类型,然后调用成员。

您还可以考虑将此功能封装在通用方法中,这使得整个过程更加容易处理:

public void doSomething<T>()
{
    var myGenObj = new MyGenericClass<T>();
    myGenObj.doSomeGenStuff();
}

如果您需要支持 Type 对象,可以使用一个使用反射欺骗的重载:

public void doSomething(Type _type)
{
    this.GetType().GetMethod("doSomething", Type.EmptyTypes)
        .MakeGenericMethod(_type)
        .Invoke(this, null);
}

谢谢,不确定该选谁作为答案,但人们似乎更喜欢Skeet的回答。很抱歉你得和他竞争 :) - RayLoveless

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接