将实例化的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的意义上,在运行时仍然是完全键入如你所期望的那样。