C# Reflection.Emit引发BadImageFormatException异常

C# Reflection.Emit引发BadImageFormatException异常,c#,reflection,reflection.emit,C#,Reflection,Reflection.emit,我试图在运行时生成一个新的类/对象 阅读之后,我设法实现了每一件事,一切都像我需要的那样 但当我尝试实例化我的新对象时,我收到了一个BadImageFormatException 这似乎是一个类似的问题,但尚未解决 这是我的代码: 字段: internal class Field { public string FieldName; public Type FieldType; public string Value; } var xx = new

我试图在运行时生成一个新的类/对象

阅读之后,我设法实现了每一件事,一切都像我需要的那样

但当我尝试实例化我的新对象时,我收到了一个
BadImageFormatException

这似乎是一个类似的问题,但尚未解决

这是我的代码:

字段:

internal class Field {
      public string FieldName;
      public Type FieldType;
      public string Value;
    }
var xx = new List<Field>(new[] { new Field { FieldName = "Name", FieldType = typeof(string), Value = "Hello World" },
        new Field { FieldName = "Id", FieldType = typeof(int), Value = "1" } });
      this.DoVodoo(xx);
生成器代码:

internal class Field {
      public string FieldName;
      public Type FieldType;
      public string Value;
    }
var xx = new List<Field>(new[] { new Field { FieldName = "Name", FieldType = typeof(string), Value = "Hello World" },
        new Field { FieldName = "Id", FieldType = typeof(int), Value = "1" } });
      this.DoVodoo(xx);
var xx=new List(new[]{new Field{FieldName=“Name”,FieldType=typeof(string),Value=“Hello World”},
新字段{FieldName=“Id”,FieldType=typeof(int),Value=“1”});
这是DoVodoo(xx);
魔法

private dynamic DoVodoo(IEnumerable<Field> fields) {
      var aName = new AssemblyName("DynamicAssemblyExample");
      var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave);

      var mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");

      // Create class with all needed Properties
      var tb = mb.DefineType("ParamRow", TypeAttributes.Public, typeof(object));
      foreach (var field in fields) {
        var pb = tb.DefineProperty(field.FieldName, PropertyAttributes.None, CallingConventions.HasThis, field.FieldType, null);

        var getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
        // Define the "get" accessor method for the Property.
        var custNameGetPropMthdBldr = tb.DefineMethod($"get_{field.FieldName}", getSetAttr, typeof(string), Type.EmptyTypes);

        var custNameGetIL = custNameGetPropMthdBldr.GetILGenerator();

        custNameGetIL.Emit(OpCodes.Ldarg_0);
        custNameGetIL.Emit(OpCodes.Ldfld, custNameGetPropMthdBldr);
        custNameGetIL.Emit(OpCodes.Ret);

        // Define the "set" accessor method for CustomerName.
        var custNameSetPropMthdBldr = tb.DefineMethod($"set_{field.FieldName}", getSetAttr, null, new[] { typeof(string) });

        var custNameSetIL = custNameSetPropMthdBldr.GetILGenerator();

        custNameSetIL.Emit(OpCodes.Ldarg_0);
        custNameSetIL.Emit(OpCodes.Ldarg_1);
        //custNameSetIL.Emit(OpCodes.Stfld, custNameGetPropMthdBldr);
        custNameSetIL.Emit(OpCodes.Stfld, custNameSetPropMthdBldr);
        custNameSetIL.Emit(OpCodes.Ret);

        // Last, we must map the two methods created above to our PropertyBuilder to 
        // their corresponding behaviors, "get" and "set" respectively. 
        pb.SetGetMethod(custNameGetPropMthdBldr);
        pb.SetSetMethod(custNameSetPropMthdBldr);
      }

      var finalType = tb.CreateType();

      var result = new List<object>();

      foreach (var field in fields) {
        var inst = ab.CreateInstance(finalType.Name);
        finalType.GetProperty(field.FieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).SetValue(inst, field.Value); //<-- Here comes the trouble
        result.Add(inst);
      }
      return result;}
私有动态DoVodoo(IEnumerable字段){
var aName=new AssemblyName(“DynamicAssemblyExample”);
var ab=AppDomain.CurrentDomain.DefinedDynamicAssembly(aName,AssemblyBuilderAccess.RunAndSave);
var mb=ab.definedDynamicModule(aName.Name,aName.Name+“.dll”);
//创建具有所有必需属性的类
var tb=mb.DefineType(“ParamRow”,TypeAttributes.Public,typeof(object));
foreach(字段中的变量字段){
var pb=tb.DefineProperty(field.FieldName,PropertyAttributes.None,CallingConventions.HasThis,field.FieldType,null);
var getSetAttr=MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.hidebysing;
//为属性定义“get”访问器方法。
var custNameGetPropMthdBldr=tb.DefineMethod($“get_{field.FieldName}”,getSetAttr,typeof(string),Type.EmptyTypes);
var custNameGetIL=custNameGetPropMthdBldr.GetILGenerator();
custnamegtil.Emit(操作码.Ldarg_0);
Emit(opcode.Ldfld、custNameGetPropMthdBldr);
custnamegtil.Emit(操作码.Ret);
//为CustomerName定义“set”访问器方法。
var custnametpropmthdbldr=tb.DefineMethod($“set{field.FieldName}”,getSetAttr,null,new[]{typeof(string)});
var custNameSetIL=custNameSetPropMthdBldr.GetILGenerator();
custNameSetIL.Emit(操作码.Ldarg_0);
custNameSetIL.Emit(操作码.Ldarg_1);
//Emit(opcode.Stfld、custNameGetPropMthdBldr);
Emit(opcode.Stfld、custNameSetPropMthdBldr);
custNameSetIL.Emit(操作码.Ret);
//最后,我们必须将上面创建的两个方法映射到我们的PropertyBuilder
//它们相应的行为分别是“get”和“set”。
pb.SetGetMethod(custNameGetPropMthdBldr);
pb.SetSetMethod(custNameSetPropMthdBldr);
}
var finalType=tb.CreateType();
var result=新列表();
foreach(字段中的变量字段){
var inst=ab.CreateInstance(finalType.Name);

finalType.GetProperty(field.FieldName,BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).SetValue(inst,field.Value);//得到的异常的
。消息
是重要的一位:

字段标记超出范围

这表明它不了解要在
ldfld
/
stfld
中使用哪个字段,这是因为您向它传递的是方法令牌(
custNameGetPropMthdBldr
/
custnametpropmthdbldr
),而不是字段令牌

您需要定义并使用一个字段:

var fb = tb.DefineField("__" + field.FieldName, field.FieldType, FieldAttributes.Private);
// ...
custNameGetIL.Emit(OpCodes.Ldarg_0);
custNameGetIL.Emit(OpCodes.Ldfld, fb);
custNameGetIL.Emit(OpCodes.Ret);
// ...
custNameSetIL.Emit(OpCodes.Ldarg_0);
custNameSetIL.Emit(OpCodes.Ldarg_1);
custNameSetIL.Emit(OpCodes.Stfld, fb);
custNameSetIL.Emit(OpCodes.Ret);
还请注意,在通过反射创建对象时,使用
类型
比使用名称更有效;这很好:

var inst = Activator.CreateInstance(finalType);

我将在调试器中查看它,看看是否可以发现错误,但是:如果您想要一种避免错误并获得良好错误消息的好方法,请尝试-它是IL emit的包装器(但概念上是相同的),旨在使它很难失败(或者至少很容易找出失败的原因)先生,你是个救命恩人。我有点尴尬,我错过了backingfield*-.-@lokusking我似乎记得Sigil在编译时会显示这个错误;当调用方法发出字段访问时,方法签名要求你传递一个field对象。这是一个很好的库,可以让IL更容易正确。通常我会给出这是一个尝试,但公司的政策使得从Nuget那里得到东西非常困难。我会在home@MarcGravell,是编译时错误,还是更显式的运行时异常?