Reflection.Emit和泛型类型

4

我正在使用 Reflection.Emit ,我想创建一个等同于以下 C# 中定义的类型的类型:

class A
{
    public Tuple<A, int> GetValue(int x)
    {
         return new Tuple<A, int>(this, x);
    }
}

诀窍在于我需要使用BCL中的通用类型,该类型使用我的自定义类型作为通用参数。
我正在处理以下代码片段:
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<,>).MakeGenericType(aType, typeof(int));

var attrs = MethodAttributes.Public;
var method = aType.DefineMethod("GetValue", attrs, tupleType, new [] { typeof(int) });
var gen = method.GetILGenerator();

gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);

// here is the fail:
var ctor = tupleType.GetConstructor(new [] { typeof(int), aType } );
gen.Emit(OpCodes.Newobj, ctor);

调用GetConstructor出现以下异常:

NotSupportedException:不支持指定的方法。

基本上,它不允许我获取仅引用我的自定义类型的类型的构造函数,也不能在发出其方法体之前完成该类型的最终处理。

真的无法摆脱这个恶性循环吗?


我在原始问题中添加了有关异常的信息。 - Impworks
2
也许你没有看到我在你之前的问题中留下的最后一条评论。我在这里重复一遍:Reflection.Emit太弱了,不能用来构建真正的编译器。它非常适合像在LINQ查询中发出动态调用站点和表达式树这样的小玩具编译任务,但对于编译器中你将面临的那些问题,你很快就会超出其能力范围。使用CCI而不是Reflection.Emit。 - Eric Lippert
@EricLippert,我已经阅读了评论,但是建议使用CCI而不是Reflection.Emit并不是很有帮助,因为这意味着我几乎必须从头开始重写我的应用程序。我很想看到哪些使用Reflection.Emit无法完成的示例,以避免进一步的失败。 - Impworks
如果你选择了错误的工具,那么你浪费的时间就是过眼云烟。你越早开始使用正确的工具重新开始,你就能越快完成。 - Eric Lippert
可能是Reflection-generated and generic types的重复问题。 - Peter Ritchie
显示剩余5条评论
1个回答

5

由于某些原因,您需要使用GetConstructor()的静态重载来实现这一点。在您的情况下,代码可能如下所示:

var ctor = TypeBuilder.GetConstructor(
    tupleType, typeof(Tuple<,>).GetConstructors().Single());

哇!这真的有效!我甚至通过GetMethod()成功获取了属性访问器。 - Impworks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接