Mono.Cecil自动实现属性访问后备字段

时间:2015-08-19 17:29:22

标签: c# code-injection mono.cecil

我正在使用x = x + [2]在自动实现的属性设置器中注入一些Mono.Cecil代码。问题是,我可以从IL对象引用它,但是当我向该引用注入TypeDefinition.Fields指令(在ldfld指令之后)时,它会导致应用程序中断,{{1引发异常。我还尝试反编译ldarg.0并获得异常CLR invalid program detected。所以这就像我在编译器创建它之前尝试访问后备字段,但不知怎的ILSpy可以在加载程序集时看到它。

Mono.Cecil argument out of range exepction in get_Item(int32) method

这是注射前setter的样子:

Mono.Cecil

这是注射码:

public class ILTesting
{
    public int Counter { get; set; }
} 

这是IL我得到的:

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)); 中看起来根本没有支持字段。

1 个答案:

答案 0 :(得分:1)

问题解决了!它不是属性,而是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)));