2

在我的应用程序中,我需要动态创建一个包含多个属性的类型。我知道在这种情况下,必须使用 ILGenerator 为属性的 getter 和 setter 方法生成 CIL。

通过反复试验,我终于得到了以下代码,它为我生成了一个 setter 方法:

MethodBuilder setMethod = customTypeBuilder.DefineMethod(propertyName + "_set", MethodAttributes.Public | MethodAttributes.HideBySig, null, new Type[] {propertyType});
ILGenerator setIlGenerator = setMethod.GetILGenerator();
setIlGenerator.Emit(OpCodes.Ldarg_0);
setIlGenerator.Emit(OpCodes.Ldarg_1);
setIlGenerator.Emit(OpCodes.Stfld, backingField);
setIlGenerator.Emit(OpCodes.Ret);

该代码运行良好,但有一点我不明白。为什么需要调用“Ldarg_0”指令?

我知道它指的是方法的隐式第一个参数,即“this”引用,因此设置器的实际值存储在第二个参数中。我认为只调用 Ldarg_1 指令就足够了,这会将第二个参数推入堆栈(最后,在设置器中,我不需要检查“this”引用,所以我不需要用它做任何事情),但是当我尝试设置属性的值时,这会导致 TargetInvocationException 被抛出。

谢谢!

4

1 回答 1

4

如果您没有将“this”值压入堆栈,如何Stfld知道要更改哪个对象的字段?您可能正在尝试编写这样的设置器:

public int Bizarre
{
    set { otherObject.Field = value; }
}

基本上,记录Stfld在堆栈上需要两个值:一个用于新值的“目标”,另一个用于值本身。诚然,ECMA 335 中的堆栈转换图更加清晰:

…, obj, value => …,

换句话说:“stfld 将从堆栈中弹出顶部的两个元素”。

于 2010-08-12T20:12:56.737 回答