gpt4 book ai didi

c# - Mono.Cecil 自动实现的属性访问支持字段

转载 作者:行者123 更新时间:2023-11-30 12:43:03 24 4
gpt4 key购买 nike

我正在使用 Mono.Cecil 在自动实现的属性 setter 中注入(inject)一些 IL 代码。问题是,我可以从 TypeDefinition.Fields 对象中获取对它的引用,但是当我注入(inject) ldfld 指令时(在 ldarg.0 指令 ofc 之后)使用该引用会导致应用程序中断,并引发 CLR invalid program detected 异常。我还尝试反编译 ILSpy 并得到异常 Mono.Cecil argument out of range exepction in get_Item(int32) method。所以这就像我试图在编译器创建支持字段之前访问它,但不知何故 Mono.Cecil 可以在加载程序集时看到它。

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

这是 setter 在注入(inject)之前的样子:

IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld int32 SyringeWpfTest.ILTesting::'<Counter>k__BackingField'
IL_0007: ret

这是注入(inject)代码:

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

因此注入(inject)代码没有中断,对支持字段的引用存在,但在 IL 中看起来根本没有支持字段。

最佳答案

问题解决了!这不是属性(property),而是 IL 的工作方式。我用代码做了一个完整的属性:

private int _counter;

public int Counter
{
get { return _counter; }
set
{
if (_counter != value)
{
_counter = value;
NotifyUI();
}
}
}

我在 ILSpy 中打开程序集,IL 代码就像我注入(inject)到自动实现的属性一样。但是后来我反编译了 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# - Mono.Cecil 自动实现的属性访问支持字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32101989/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com