我正在使用以下代码创建基于键/值的类类型:
/// <summary>
/// Generate a new class type using the schema info in a list of DataGridHeader
/// </summary>
/// <param name="header"></param>
/// <returns></returns>
static public Type BuildType(IList<DataGridHeader> header) {
AppDomain domain = Thread.GetDomain();
AssemblyName assemblyName = new AssemblyName {Name = "DynamicDataGridDataAsm"};
AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(assemblyName,AssemblyBuilderAccess.RunAndSave);
ModuleBuilder dynamicDataGridDataModule = assemblyBuilder.DefineDynamicModule("DynamicDataGridDataModule", "DynamicDataGridDataModule.dll");
TypeBuilder ivTypeBld = dynamicDataGridDataModule.DefineType("DynamicDataGridData", TypeAttributes.Public);
foreach (var kvp in header) {
ImplementProperty(ivTypeBld, kvp.Name, typeof(string));
}
ImplementProperty(ivTypeBld, "Value", typeof(string));
return ivTypeBld.CreateType();
}
/// <summary>
/// Generates propery Get/Set methods for a property by name and type
/// </summary>
/// <param name="type"></param>
/// <param name="propertyName"></param>
/// <param name="propertyType"></param>
private static void ImplementProperty(TypeBuilder type, string propertyName, Type propertyType) {
FieldBuilder field = type.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder property = type.DefineProperty(propertyName, PropertyAttributes.None, propertyType, Type.EmptyTypes);
MethodBuilder getter = type.DefineMethod("get_" + propertyName, MethodAttributes.Public, propertyType, Type.EmptyTypes);
ILGenerator getterIL = getter.GetILGenerator();
getterIL.Emit(OpCodes.Ldarg_0);
getterIL.Emit(OpCodes.Ldfld, field);
getterIL.Emit(OpCodes.Ret);
MethodBuilder setter = type.DefineMethod("set_" + propertyName, MethodAttributes.Public, typeof(void), new Type[] { propertyType });
ILGenerator setterIL = setter.GetILGenerator();
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldflda, field);
setterIL.Emit(OpCodes.Ldarg_1);
setterIL.Emit(OpCodes.Ldstr, propertyName);
setterIL.Emit(OpCodes.Call, propertyType);
setterIL.Emit(OpCodes.Ret);
property.SetGetMethod(getter);
property.SetSetMethod(setter);
}
构建类型后,我尝试使用字典值填充新属性成员:
static public object GetInstance(Type type, Dictionary<string, string> data) {
//default construct the new type
ConstructorInfo constructorInfo = type.GetConstructor(Type.EmptyTypes);
object row = constructorInfo.Invoke(null);
//Call set on each property
foreach (var kv in data) {
try {
// PropertyInfo prop = row.GetType().GetProperty(kv.Key, BindingFlags.Public | BindingFlags.Instance);
// if (null != prop && prop.CanWrite) {
// prop.SetValue(row, kv.Value, null);
// }
type.InvokeMember(kv.Key,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder,
row,
new object[] {kv.Value});
}
catch (Exception e) {
Console.WriteLine(e);
}
}
调用InvokeMember或PropertyInfo.SetValue导致异常
“{System.Reflection.TargetInvocationException:调用目标抛出了异常.---&gt; System.BadImageFormatException:错误的方法标记。 at DynamicDataGridData.set_Value(String) ---内部异常堆栈跟踪结束--- at System.RuntimeMethodHandle.InvokeMethod(Object target,Object [] arguments,Signature sig,Boolean constructor) at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj,Object [] parameters,Object [] arguments) 在System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags invokeAttr,Binder binder,Object []参数,CultureInfo文化) at System.RuntimeType.InvokeMember(String name,BindingFlags bindingFlags,Binder binder,Object target,Object [] providedArgs,ParameterModifier [] modifiers,CultureInfo culture,String [] namedParams) at System.Type.InvokeMember(String name,BindingFlags invokeAttr,Binder binder,Object target,Object [] args) at DSI.MobileClient.Models.DataGridDataTypeBuilder.GetInstance(Type type,Dictionary`2 data)in c:\ DSISource_Global \ v7 \ Development \ Team5 \ DSI.MobileClient \ Models \ DataGridDataTypeBuilder.cs:line 33}“
我一直在调查set属性构建器的.Emit部分中可能出现的问题,但是我还没想到我错过了什么。
调试器显示我正在尝试设置的属性。
**修改
认为这条线不正确:
setterIL.Emit(OpCodes.Call, propertyType);
现在尝试理解复制和粘贴 - 用此替换setter emit可能有效:
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldarg_1);
setterIL.Emit(OpCodes.Stfld, field);
setterIL.Emit(OpCodes.Ret);