将实例化的System.Type传递为generics类的types参数

标题是一种晦涩的。 我想知道的是,如果这是可能的:

string typeName = <read type name from somwhere>; Type myType = Type.GetType(typeName); MyGenericClass<myType> myGenericClass = new MyGenericClass<myType>(); 

显然,MyGenericClass被描述为:

 public class MyGenericClass<T> 

现在,编译器抱怨说'找不到'myType'types或名称空间。“有一种方法可以做到这一点。

你不能没有反思就做到这一点。 不过,你可以用reflection做到这一点。 这是一个完整的例子:

 using System; using System.Reflection; public class Generic<T> { public Generic() { Console.WriteLine("T={0}", typeof(T)); } } class Test { static void Main() { string typeName = "System.String"; Type typeArgument = Type.GetType(typeName); Type genericClass = typeof(Generic<>); // MakeGenericType is badly named Type constructedClass = genericClass.MakeGenericType(typeArgument); object created = Activator.CreateInstance(constructedClass); } } 

注意:如果您的generics类接受多种types,则在省略types名称时必须包含逗号,例如:

 Type genericClass = typeof(IReadOnlyDictionary<,>); Type constructedClass = genericClass.MakeGenericType(typeArgument1, typeArgument2); 

不幸的是没有。 generics参数必须在编译时可parsing为1)有效types或2)另一个generics参数。 如果没有使用reflection的大锤,就无法基于运行时值创buildgenerics实例。

我的要求稍有不同,但希望可以帮助别人。 我需要从configuration中读取types,并dynamic地实例化genericstypes。

 namespace GenericTest { public class Item { } } namespace GenericTest { public class GenericClass<T> { } } 

最后,这里是你如何称呼它。 用倒退来定义types 。

 var t = Type.GetType("GenericTest.GenericClass`1[[GenericTest.Item, GenericTest]], GenericTest"); var a = Activator.CreateInstance(t); 

一些额外的如何运行剪刀代码。 假设你有一个类似的类

 public class Encoder() { public void Markdown(IEnumerable<FooContent> contents) { do magic } public void Markdown(IEnumerable<BarContent> contents) { do magic2 } } 

假设在运行时你有一个FooContent

如果你能够在编译时绑定,你会想

 var fooContents = new List<FooContent>(fooContent) new Encoder().Markdown(fooContents) 

但是,你不能在运行时做到这一点。 要在运行时执行此操作,您可以按照以下方式进行操作:

 var listType = typeof(List<>).MakeGenericType(myType); var dynamicList = Activator.CreateInstance(listType); ((IList)dynamicList).Add(fooContent); 

要dynamic调用Markdown(IEnumerable<FooContent> contents)

 new Encoder().Markdown( (dynamic) dynamicList) 

请注意方法调用中的dynamic使用。 在运行时, List<FooContent>将是List<FooContent> (另外也是IEnumerable<FooContent> ),因为即使使用dynamic仍然植根于强types语言,运行时联编程序将select适当的Markdown方法。 如果没有确切的types匹配,它将查找对象参数方法,如果两者都不匹配,将会引发运行时联编程序exception,提示没有方法匹配。

这种方法显而易见的缺点是编译时的types安全性大大降低。 尽pipe如此,代码沿着这些线将允许您运行在一个非常dynamic的意义上,在运行时仍然是完全键入如你所期望的那样。