我尝试使用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]以查看异常。 什么想法可能是错的?
答案 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。