在我的应用程序中,我需要动态创建一个包含多个属性的类型。我知道在这种情况下,必须使用 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!
发布评论
评论(1)
如果您没有将“this”值压入堆栈,Stfld 如何知道要更改哪个对象的字段?您可能会尝试编写这样的设置器:
基本上,
Stfld
是 记录了,堆栈上需要两个值:一个用于新值的“目标”,另一个用于值本身。诚然,ECMA 335 中的堆栈转换图更清晰:换句话说:“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: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:In other words: "stfld will pop the top two elements off the stack".