发出属性以设置字典值

时间:2019-07-02 08:58:23

标签: c# cil reflection.emit

我尝试为动态程序集中的属性发出set字段方法。

所需的C#代码是:

private readonly Dictionary<string, object> propertyBag = new Dictionary<string, object>();

public string PropertyName
{
    set { propertyBag["PropertyName"] = value; }
}

PropertyName及其类型必须是动态的

我发出二传手的代码是:

PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, Type.EmptyTypes);
FieldBuilder fieldBuilder = typeBuilder.DefineField("propertyBag", typeof(Dictionary<string, object>), FieldAttributes.Private);

MethodBuilder setMethodBuilder = typeBuilder.DefineMethod($"set_{propertyName}", MethodAttributes.Public | MethodAttributes.HideBySig, null, new[] { propertyType });
ILGenerator setIL = setMethodBuilder.GetILGenerator();
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Ldfld, fieldBuilder);
setIL.Emit(OpCodes.Ldstr, propertyName);
setIL.Emit(OpCodes.Callvirt, fieldBuilder.FieldType.GetMethod("set_Item", new Type[] { typeof(string), typeof(object) }));
setIL.Emit(OpCodes.Ret);

propertyBuilder.SetSetMethod(setMethodBuilder);

运行设置属性的代码时,我有一个

  

AccessViolationException :尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

一个主意?

1 个答案:

答案 0 :(得分:1)

set_item的参数顺序似乎已关闭。

看看这个反编译的例子,value(arg1)应该是第二个参数,而不是第一个:

IL_0000: ldarg.0
IL_0001: ldfld class [System.Private.CoreLib]System.Collections.Generic.Dictionary`2<string, object> C::propertyBag
IL_0006: ldstr "PropertyName"
IL_000b: ldarg.1
IL_000c: callvirt instance void class [System.Private.CoreLib]System.Collections.Generic.Dictionary`2<string, object>::set_Item(!0, !1)
IL_0011: ret

来自这里: sharplab.io