65

我有一个将通用类型作为其初始化的一部分的类。

public class AnimalContext<T>
{
    public DoAnimalStuff()
    {
        //AnimalType Specific Code
    }
}

我现在能做的是

AnimalContext<Donkey> donkeyContext = new AnimalContext<Donkey>();
AnimalContext<Orca> orcaContext = new AnimalContext<Orca>();

但是我需要/想要做的是能够声明一个初始化为仅在运行时才知道的类型的 AnimalContext。例如,

Animal a = MyFavoriteAnimal(); //returns an instance of a class 
                               //implementing an animal
AnimalContext<a.GetType()> a_Context = new AnimalContext<a.GetType()>();
a_Context.DoAnimalStuff();

这甚至可能吗?我似乎无法在网上找到答案。

4

3 回答 3

64

这部分的意思可能的:

new AnimalContext<a.GetType()>();

显然,确切的语法是错误的,我们将解决这个问题,但是当您直到runtime才知道类型参数时,可以在运行时构造泛型类型的实例。

这部分的意思不是

AnimalContext<a.GetType()> a_Context

也就是说,如果您在编译时不知道类型参数,就不可能将变量键入为泛型类型。泛型是编译时构造,依赖于在编译时提供类型信息。鉴于此,如果您在编译时不知道类型,您将失去泛型的所有好处。

现在,要在运行时构造泛型类型的实例,而您直到运行时才知道类型,您可以说:

var type = typeof(AnimalContext<>).MakeGenericType(a.GetType());
var a_Context = Activator.CreateInstance(type);   

请注意,编译时类型a_contextobject. 您必须转换a_context为定义您需要访问的方法的类型或接口。通常你会看到人们在这里做的是让泛型类型AnimalContext<T>实现一些接口(比如IAnimalContext从定义他们需要的方法的非泛型基类(比如AnimalContext)继承(这样你就可以a_context转换为接口或非-通用基类)。另一种选择是使用dynamic. 但同样,请记住,这样做并没有泛型类型的任何好处。

于 2013-07-08T04:15:19.010 回答
11

您可以通过使用MakeGenericType方法使用泛型类型的反射并利用dynamic关键字:

var type = typeof (AnimalContext<>).MakeGenericType(a.GetType());
dynamic a_Context = Activator.CreateInstance(type);

所以你可以打电话:

a_Context.DoAnimalStuff();

或者再次使用反射调用方法:

type.GetMethod("DoAnimalStuff").Invoke(a_Context, null);
于 2013-07-08T04:12:37.227 回答
6

您需要使用反射创建类型,然后调用该类型。就像是:

Animal a = MyFavoriteAnimal();
var contextType = typeof(EsbRepository<>).MakeGenericType(a.GetType());

dynamic context = Activator.CreateInstance(contextType);
context.DoAnimalStuff();

使用动态意味着上下文变量将在运行时进行评估,允许您调用 DoAnimalStuff 方法。

于 2013-07-08T04:13:56.647 回答