为什么CIL方法中需要将每个参数加载到堆栈上?

发布于 2024-09-14 10:54:47 字数 805 浏览 11 评论 0 原文

在我的应用程序中,我需要动态创建一个包含多个属性的类型。我知道在这种情况下,必须使用 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 指令就足够了,这会将第二个参数推入堆栈(最后,在设置器中,我不需要检查“this”引用,因此我不需要对其进行任何操作),但这会导致当我尝试设置该属性的值时抛出 TargetInitationException 。

谢谢你!

in my application I need to dynamically create a type that contains multiple properties. I am aware that in cases such as this, one has to generate an CIL for both getter and setter methods of a property by using an ILGenerator.

More by a trial and error than anything else, I've finally arrived to the following code that generates a setter method for me:

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);

The code works well enough, but there is one thing I don't understand about it. Why is it necessary to call the 'Ldarg_0' instruction?

I know that it refers to the implicit first argument of the method, the "this" reference, so the actual value for the setter is stored in the second argument. I thought that it should be sufficient to call the Ldarg_1 instruction only, which would push the second argument to the stack (in the end, in the setter, I have no need of examining the "this" reference so I don't need to do anything with it), but this results in the TargetInvocationException being thrown when I attempt to set the value of the property.

Thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

嘿哥们儿 2024-09-21 10:54:47

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

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

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

…, obj, value => …,

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

If you didn't push the "this" value onto the stack, how would Stfld know which object's field to change? You could be trying to write a setter like this:

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

Basically, Stfld is documented to need two values on the stack: one for the "target" of the new value, and one for the value itself. Admittedly the stack transition diagram in ECMA 335 is clearer:

…, obj, value => …,

In other words: "stfld will pop the top two elements off the stack".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文