reflection生成和generics类型

我在Reflection.Emit和类型管理方面又遇到了一个令人讨厌的时刻。

比如说,我有一个名为MyType的类型,它在动态生成的程序集中定义。 调用MyType.GetMethods()导致NotSupportedException ,这使我减少了编写自己的包装器和查找表的能力。 但是,当我在使用我自己的类型作为generics参数的标准generics类型上调用GetMethods()或任何其他内省方法时,也会发生同样的情况:

  • Tuple =>工作正常
  • Tuple =>exception

我可以从generics类型定义中获取方法列表:

typeof(Tuple<int, MyType).GetGenericTypeDefinition().GetMethods()

但是,这些方法具有通用占位符而不是实际值(如T1TResult等)。我不想编写另一个将通用参数追溯到其原始值的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 

所以问题是:

  1. 如何检测类型是否可以安全地调用GetMethods()和类似的方法?
  2. 如果类型不安全,如何获取方法的实际列表及其通用参数值?

我在后续问题中得到了答案。 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体中取出。