为什么有必要在CIL方法中将每个参数加载到堆栈中?

时间:2010-08-12 20:07:11

标签: .net stack cil arguments ilgenerator

在我的应用程序中,我需要动态创建一个包含多个属性的类型。我知道在这种情况下,必须使用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”引用,因此setter的实际值存储在第二个参数中。我认为仅调用Ldarg_1指令就足够了,这会将第二个参数推送到堆栈(最后,在setter中,我不需要检查“this”引用,所以我不需要对它做任何事情),但这会导致在我尝试设置属性的值时抛出TargetInvocationException。

谢谢!

1 个答案:

答案 0 :(得分:4)

如果你没有将“this”值推到堆栈上,Stfld将如何知道哪个对象的字段会改变?您可能正在尝试编写这样的setter:

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

基本上,Stflddocumented在堆栈上需要两个值:一个用于新值的“目标”,另一个用于值本身。无可否认,ECMA 335中的堆栈转换图更清晰:

…, obj, value => …,

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