繁体   English   中英

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

[英]Generate code for generic nested class with 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]以查看异常。 任何想法可能有什么问题吗?

事实证明,嵌套类实际上无法访问其父代的泛型类型参数/参数,并且要使其结构良好,它们实际上需要重新声明其父代的所有泛型类型参数(例如,参见此旧博客文章 ,或者ECMA CLI规范的 I.10.7.1部分,其中详细介绍了有关CLS兼容性的要求。 因此,您需要执行以下操作:

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

您仍然遇到其他一些问题(例如,您的apply方法的IL无效),但这至少应足以阻止您使用PEVerify。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM