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