Reflection.Emit抛出BadImageFormatException

时间:2016-07-15 06:43:34

标签: c# reflection reflection.emit

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

在阅读How to create a private property using PropertyBuilder之后,我设法实现了所有实施,一切都像我需要它。

但是一旦我试图实现我的新对象,我就会收到BadImageFormatException

这似乎是一个类似的问题,但未解决Is there any way to instrument System.Reflection.Emit?

这是我的代码:

字段:

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);

魔术

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;}

如何设置我新创建的类型ParamRow,我们非常感激。

加成-问题: 为什么会有BadImageFormatException

其他信息:

  • .Net-Framework 4.6.1
  • 编译器目标是x86
  • 从来没有Reflection.Emit之前

1 个答案:

答案 0 :(得分:3)

你得到的例外的$letters = str_split($_POST["message"]); // spliting string to letters array foreach ($letters as $letter) { if (' ' == $letter) { continue; } $letter = strtolower($letter); echo $store[$letter]; // values from $store array call_user_func($store[$letter]); // calling big letter function } 是重要的一点:

  

字段标记超出范围。

这告诉您,您无法理解要在.Message / ldfld中使用哪个字段 - 这是因为您正在通过方法令牌(stfld / custNameGetPropMthdBldr)而不是字段令牌。

您需要定义并使用字段:

custNameSetPropMthdBldr

另请注意,在通过反射创建对象时,使用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); 比使用名称更有效;这很好用:

Type