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