Почему необходимо загружать каждый аргумент в стек в методе CIL?
В моем приложении мне нужно динамически создать тип, который содержит несколько свойств. Мне известно, что в таких случаях необходимо сгенерировать CIL для методов получения и установки свойства с помощью 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'?
Я знаю, что это относится к неявному первому аргументу метода, ссылке "this", поэтому фактическое значение для установщика сохраняется во втором аргументе. Я подумал, что должно быть достаточно вызвать только инструкцию Ldarg_1, которая будет помещать второй аргумент в стек (в конце концов, в установщике мне не нужно проверять ссылку "this", поэтому мне не нужно делать что-нибудь с этим), но это приводит к тому, что TargetInvocationException генерируется, когда я пытаюсь установить значение свойства.
Спасибо!
1 ответ
Если бы вы не поместили значение "this" в стек, как бы Stfld
знать, какое поле объекта нужно изменить? Вы могли бы пытаться написать сеттер как это:
public int Bizarre
{
set { otherObject.Field = value; }
}
В принципе, Stfld
задокументировано, что в стеке требуется два значения: одно для "цели" нового значения и одно для самого значения. По общему признанию диаграмма перехода стека в ECMA 335 более ясна:
…, obj, value => …,
Другими словами: "stfld вытолкнет два верхних элемента из стека".