使用Reflection.Emit为通用嵌套类生成代码

时间:2015-08-31 09:26:49

标签: c# generics nested reflection.emit

我尝试使用Reflection.Emit生成代码,它看起来与C#编译器为此生成的内容完全相同或类似:

public interface Function<in T, out Res>
{
    Res Apply(T p);
}


public class MyMain<A>
{
    class Closure : Function<A, A>
    {
        public A Apply(A p)
        {
            throw new NotImplementedException();
        }
    }
}

如果我使用某种真实类型,我的代码工作正常,但当我用泛型替换它时,我得到BadImageFormatException。

    private static void CreateGenericClosures()
    {
        AssemblyName assemblyName = new AssemblyName("genericClosure");
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll");

        TypeBuilder main = moduleBuilder.DefineType("Main", TypeAttributes.Class | TypeAttributes.Public);

        Type t = typeof (Foo);

        // Defining generic param for Main class
        GenericTypeParameterBuilder[] generics = main.DefineGenericParameters("A");
        // t = generics[0]; // [1] Uncomment to enable for nested class

        var iFunctionType = typeof (Function<,>).MakeGenericType(t, t);

        TypeBuilder closure = main.DefineNestedType("Closure", TypeAttributes.Class | TypeAttributes.NestedPrivate, typeof (object));
        closure.AddInterfaceImplementation(iFunctionType);

        MethodBuilder applyMethod = closure.DefineMethod("Apply",
            MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.Public,
            CallingConventions.Standard);
        applyMethod.SetParameters(t);
        applyMethod.SetReturnType(t);

        ILGenerator body = applyMethod.GetILGenerator();
        body.Emit(OpCodes.Ldnull);
        body.Emit(OpCodes.Ret);

        closure.DefineDefaultConstructor(MethodAttributes.Public);

        closure.CreateType();
        main.CreateType();

        assemblyBuilder.Save(assemblyName.Name + ".dll", PortableExecutableKinds.Required32Bit, ImageFileMachine.I386);
    }

取消注释[1]以查看异常。 什么想法可能是错的?

1 个答案:

答案 0 :(得分:0)

事实证明,嵌套类实际上不能访问其父类的泛型类型参数/参数,并且格式正确,它们实际上需要重新声明其父类的所有泛型类型参数(参见例如{{3 } {或this old blog post的I.10.7.1节,其中详细介绍了CLS兼容性的要求)。所以你需要做的是这样的事情:

...
var t = closure.DefineGenericParameters("A")[0];
var iFunctionType = typeof(Function<,>).MakeGenericType(t, t);
closure.AddInterfaceImplementation(iFunctionType);
...

你还有其他一些问题(例如你的申请方法的IL无效),但这至少应该阻止你使用PEVerify。