反射生成和泛型类型

时间:2013-03-26 20:35:32

标签: c# reflection.emit

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

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

  • Tuple<int, string> =&gt;工作正常
  • Tuple<int, MyType> =&gt;例外

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

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. 如果类型不安全,如何获取实际的方法列表及其通用参数值?

2 个答案:

答案 0 :(得分:7)

我在follow-up question得到了答案。 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);

答案 1 :(得分:4)

我会向您推荐文档:

Defining a Type with Reflection Emit

  

虽然TypeBuilder是从Type派生的,但Type类中定义的一些抽象方法并未在TypeBuilder中完全实现。这些TypeBuilder方法抛出NotSupportedException。通过使用Type.GetType或Assembly.GetType检索创建的类型并反映检索到的类型,可以获得所需的功能。

所以:

  

如何检测类型是否可以安全地调用GetMethods()和类似的方法?

如果类型对象是TypeBuilder,或者类型引用的是TypeBuilder的任何类型,那么这样做是不安全的。

  

如果类型不安全,我如何得到实际的方法列表及其通用参数值?

我会再次向您推荐文档。实际上将类型发射到装配体中,然后将其从装配体中取出。