reflection生成和generics类型
我在Reflection.Emit
和类型管理方面又遇到了一个令人讨厌的时刻。
比如说,我有一个名为MyType
的类型,它在动态生成的程序集中定义。 调用MyType.GetMethods()
导致NotSupportedException
,这使我减少了编写自己的包装器和查找表的能力。 但是,当我在使用我自己的类型作为generics参数的标准generics类型上调用GetMethods()
或任何其他内省方法时,也会发生同样的情况:
-
Tuple
=>工作正常 -
Tuple
=>exception
我可以从generics类型定义中获取方法列表:
typeof(Tuple<int, MyType).GetGenericTypeDefinition().GetMethods()
但是,这些方法具有通用占位符而不是实际值(如T1
, TResult
等)。我不想编写另一个将通用参数追溯到其原始值的kludge。
代码示例:
var asmName = new AssemblyName("Test"); var access = AssemblyBuilderAccess.Run; var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, access); var module = asm.DefineDynamicModule("Test"); var aType = module.DefineType("A"); var tupleType = typeof(Tuple); var tuple = tupleType.MakeGenericType(new [] { typeof(int), aType }); tuple.GetProperty("Item1"); // <-- here's the error
所以问题是:
- 如何检测类型是否可以安全地调用
GetMethods()
和类似的方法? - 如果类型不安全,如何获取方法的实际列表及其通用参数值?
我在后续问题中得到了答案。 TypeBuilder
类有一堆静态重载,完全可以做到这一点:
var genericTuple = typeof(Tuple<,>); var myTuple = genericTuple.MakeGenericType(typeof(int), myType); var ctor = TypeBuilder.GetConstructor(myTuple, genericTuple.GetConstructors().First());
奇怪的是, GetProperty
并没有过载。 但是,仍然可以使用GetMethod
解析属性getter和setter:
var genericGetter = typeof(Tuple<,>).GetProperty("Item1").GetMethod; var actual = TypeBuilder.GetMethod(myTuple, genericGetter);
我会把你推荐给文档:
使用reflection发射定义类型
这说
尽管TypeBuilder是从Type派生的,但Type类中定义的一些抽象方法并未在TypeBuilder中完全实现。 这些TypeBuilder方法抛出NotSupportedException。 通过使用Type.GetType或Assembly.GetType检索创建的类型并反映检索到的类型,可以获得所需的function。
所以:
如何检测类型是否可以安全地调用GetMethods()和类似的方法?
如果类型对象是TypeBuilder,或者类型引用的是TypeBuilder的任何类型,那么这样做是不安全的。
如果类型不安全,如何获取方法的实际列表及其通用参数值?
我会再次向您推荐文档。 实际上将类型发射到assembly体中,然后将其从assembly体中取出。