C# Mono.Cecil自动实现属性访问备份字段

C# Mono.Cecil自动实现属性访问备份字段,c#,code-injection,mono.cecil,C#,Code Injection,Mono.cecil,我正在使用Mono.Cecil在自动实现的属性设置器中注入一些IL代码。问题是,我可以从TypeDefinition.Fields对象获取对它的引用,但当我使用该引用注入ldfld指令(在ldarg.0指令ofc之后)时,它会导致应用程序中断,并引发CLR检测到无效程序异常。我还尝试反编译ILSpy,并在get_Item(int32)方法中得到异常Mono.Cecil参数超出范围。所以,这就像我试图在编译器创建支持字段之前访问它,但不知何故,Mono.Cecil可以在加载程序集时看到它 publ

我正在使用
Mono.Cecil
在自动实现的属性设置器中注入一些
IL
代码。问题是,我可以从
TypeDefinition.Fields
对象获取对它的引用,但当我使用该引用注入
ldfld
指令(在
ldarg.0
指令ofc之后)时,它会导致应用程序中断,并引发
CLR检测到无效程序
异常。我还尝试反编译
ILSpy
,并在get_Item(int32)方法中得到异常
Mono.Cecil参数超出范围。所以,这就像我试图在编译器创建支持字段之前访问它,但不知何故,
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
IL_0000:ldarg.0
IL_0001:ldarg.1
IL_0002:stfld int32注射器wpftest.ILTesting::'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));
var fieldName=“k\uu BackingField”;
var fieldRef=ilTestType.Fields.Single(field=>field.Name==fieldName);
var setterInstruction=property.SetMethod.Body.Instructions;
插入(0,指令.Create(OpCodes.Brfalse\S,setterInstructions.Last());
setterInstructions.Insert(0,指令.Create(操作码.Ldloc_0));
setterInstructions.Insert(0,指令.Create(OpCodes.Stloc_0));
setterInstructions.Insert(0,指令.Create(OpCodes.Ceq));
setterInstructions.Insert(0,指令.Create(opcode.Ldc_I4_0));
setterInstructions.Insert(0,指令.Create(OpCodes.Ceq));
setterInstructions.Insert(0,指令.Create(操作码.Ldarg_1));
setterInstructions.Insert(0,指令.Create(OpCodes.Ldfld,reference));
setterInstructions.Insert(0,指令.Create(操作码.Ldarg_0));
setterInstructions.Insert(0,指令.Create(OpCodes.Nop));
这是我得到的:

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_0000:nop
IL_0001:ldarg.0
IL_0002:ldfld int32注射器wpftest.ILTesting::“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:没有
IL_0012:ldarg.0
IL_0013:ldarg.1
IL_0014:stfld int32注射器Wpftest.IL测试::'k_BackingField'
IL_0019:没有
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)));