ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c# – Mono.Cecil自动实现的属性访问后备字段

2019-07-06 17:05:21  阅读:150  来源: 互联网

标签:c code-injection mono-cecil


我正在使用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.Ceq));
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中看起来根本没有支持字段.

解决方法:

问题解决了!这不是财产,而是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)));

标签:c,code-injection,mono-cecil
来源: https://codeday.me/bug/20190706/1399179.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有