从C#类型变量初始化通用变量

Pet*_*nge 42 c# generics

我有一个类,它将Generic Type作为其初始化的一部分.

public class AnimalContext<T>
{
    public DoAnimalStuff()
    {
        //AnimalType Specific Code
    }
}
Run Code Online (Sandbox Code Playgroud)

我现在能做的是

AnimalContext<Donkey> donkeyContext = new AnimalContext<Donkey>();
AnimalContext<Orca> orcaContext = new AnimalContext<Orca>();
Run Code Online (Sandbox Code Playgroud)

但我需要/想要做的是能够声明一个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();
Run Code Online (Sandbox Code Playgroud)

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

jas*_*son 43

您对此部分的意思可能的:

new AnimalContext<a.GetType()>();
Run Code Online (Sandbox Code Playgroud)

显然,准确的语法是错误的,我们会得到一点,但它可以在构造泛型类型的实例运行时,当你不知道类型参数,直到运行时.

你对这部分的意思不是:

AnimalContext<a.GetType()> a_Context
Run Code Online (Sandbox Code Playgroud)

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

现在,要在运行时不知道类型的情况下在运行时构造泛型类型的实例,您可以说:

var type = typeof(AnimalContext<>).MakeGenericType(a.GetType());
var a_Context = Activator.CreateInstance(type);   
Run Code Online (Sandbox Code Playgroud)

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

  • 每个回答的人都给出了答案,提供的信息比之前的答案多一些.一切都是正确的,质量很好,但只有一个可以被选为答案,所以我选择了最具描述性的一个.我要感谢所有回答的人,我感谢所有的帮助(特别是在周日晚上.) (4认同)
  • 如果我的类不是通用的,但内部方法是,在这种情况下我将如何使用 MakeGenericType (2认同)

cuo*_*gle 9

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

var type = typeof (AnimalContext<>).MakeGenericType(a.GetType());
dynamic a_Context = Activator.CreateInstance(type);
Run Code Online (Sandbox Code Playgroud)

所以你可以打电话:

a_Context.DoAnimalStuff();
Run Code Online (Sandbox Code Playgroud)

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

type.GetMethod("DoAnimalStuff").Invoke(a_Context, null);
Run Code Online (Sandbox Code Playgroud)


SCB*_*SCB 6

您需要使用Reflection创建类型,然后调用该类型.就像是:

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

dynamic context = Activator.CreateInstance(contextType);
context.DoAnimalStuff();
Run Code Online (Sandbox Code Playgroud)

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