Reflection.Emit 抛出 BadImageFormatException
Reflection.Emit throws BadImageFormatException
我正在尝试在运行时生成一个新的 class/object。
阅读 后,我已经设法实现了所有功能,一切都像我需要的那样。
但是当我尝试实例化我的新对象时,我收到了 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
从来没有
你得到的异常的.Message
是重要的一点:
Field token out of range.
这告诉您它不理解您要在 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
比 name 更有效;这很好用:
var inst = Activator.CreateInstance(finalType);
我正在尝试在运行时生成一个新的 class/object。
阅读
但是当我尝试实例化我的新对象时,我收到了 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
从来没有
你得到的异常的.Message
是重要的一点:
Field token out of range.
这告诉您它不理解您要在 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
比 name 更有效;这很好用:
var inst = Activator.CreateInstance(finalType);