لماذا من الضروري تحميل كل وسيطة على المكدس في طريقة CIL؟
-
28-09-2019 - |
سؤال
في طلبي ، أحتاج إلى إنشاء نوع ديناميكي يحتوي على خصائص متعددة. أدرك أنه في مثل هذه الحالات ، يتعين على المرء إنشاء CIL لكل من أساليب Getter و Setter الخاصة بالخاصية باستخدام ilgenerator.
أكثر من التجربة والخطأ أكثر من أي شيء آخر ، لقد وصلت أخيرًا إلى الكود التالي الذي يولد طريقة لي:
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"؟
أعلم أنه يشير إلى الوسيطة الأولى الضمنية للطريقة ، المرجع "هذا" ، وبالتالي يتم تخزين القيمة الفعلية للستر في الوسيطة الثانية. اعتقدت أنه يجب أن يكون كافياً استدعاء تعليمات LDARG_1 فقط ، والتي ستدفع الوسيطة الثانية إلى المكدس (في النهاية ، في Setter ، لا أحتاج إلى فحص المرجع "هذا" لذلك لا أحتاج إلى ذلك افعل أي شيء به) ، ولكن هذا ينتج عنه TargetInvocationException عندما أحاول تعيين قيمة الخاصية.
شكرًا لك!
المحلول
إذا لم تدفع القيمة "هذا" على المكدس ، فكيف يمكن Stfld
هل تعرف حقل الكائن الذي يجب تغييره؟ يمكن أن تحاول كتابة وسيلة مثل هذا:
public int Bizarre
{
set { otherObject.Field = value; }
}
أساسًا، Stfld
هو موثق للحصول على قيمتين على المكدس: واحدة لـ "الهدف" من القيمة الجديدة ، وواحدة للقيمة نفسها. من المسلم به أن مخطط انتقال المكدس في ECMA 335 أكثر وضوحًا:
…, obj, value => …,
وبعبارة أخرى: "سوف يثني STFLD العناصر الأولى من المكدس".