我正在使用Mono.Cecil在自动实现的属性设置器中注入一些IL代码.问题是,我可以从TypeDeFinition.Fields对象中引用它,但是当我使用该引用注入ldfld指令(在ldarg.0指令之后)时,它会导致应用程序中断,并且引发CLR无效程序检测到的异常.我还试图反编译ILSpy并在get_Item(int32)方法中获得异常Mono.Cecil参数超出范围的exepction.所以它就像我在编译器创建它之前尝试访问支持字段,但不知何故,Mono.Cecil在加载程序集时可以看到它.
public class ILTesting { public int Counter { get; set; } }
这是注入前setter的样子:
IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: stfld int32 SyringeWpfTest.ILTesting::'<Counter>k__backingField' IL_0007: ret
这是注射码:
var fieldName = "<" + property.Name + ">k__backingField"; var fieldRef = ilTestType.Fields.Single(field => field.Name == fieldName); var setterInstruction = property.SetMethod.Body.Instructions; setterInstructions.Insert(0,Instruction.Create(OpCodes.Brfalse_S,setterInstructions.Last())); setterInstructions.Insert(0,Instruction.Create(OpCodes.Ldloc_0)); setterInstructions.Insert(0,Instruction.Create(OpCodes.Stloc_0)); setterInstructions.Insert(0,Instruction.Create(OpCodes.Ceq)); setterInstructions.Insert(0,Instruction.Create(OpCodes.Ldc_I4_0)); setterInstructions.Insert(0,Instruction.Create(OpCodes.Ldarg_1)); setterInstructions.Insert(0,Instruction.Create(OpCodes.Ldfld,reference)); setterInstructions.Insert(0,Instruction.Create(OpCodes.Ldarg_0)); setterInstructions.Insert(0,Instruction.Create(OpCodes.nop));
这是我得到的IL:
IL_0000: nop IL_0001: ldarg.0 IL_0002: ldfld int32 SyringeWpfTest.ILTesting::'<Counter>k__backingField' IL_0007: ldarg.1 IL_0008: ceq IL_000a: ldc.i4.0 IL_000b: ceq IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: brfalse.s IL_001a IL_0011: nop IL_0012: ldarg.0 IL_0013: ldarg.1 IL_0014: stfld int32 SyringeWpfTest.ILTesting::'<Counter>k__backingField' IL_0019: nop IL_001a: ret
解决方法
问题解决了!这不是财产,而是IL的工作方式.我用代码制作了一个完整的属性:
private int _counter; public int Counter { get { return _counter; } set { if (_counter != value) { _counter = value; NotifyUI(); } } }
我在ILSpy中打开了程序集,IL代码就像我注入到自动实现的属性一样.但后来我反编译IL以查看反编译后的C#代码是什么样的,代码看起来像:
private int _counter; public int Counter { get { return _counter; } set { bool flag = _counter != value; //THIS THING MADE MY LIFE SO HARD FOR A FEW DAYS! if (flag) { _counter = value; NotifyUI(); } } }
所以,问题是在方法堆栈框架上缺少局部变量.在方法中插入局部变量后,一切都很完美.
myProperty.SetMethod.Body.Variables.Add(new VariableDeFinition(assembly.MainModul.Import(typeof(bool)));
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。