Я использую Mono.Cecil
, чтобы ввести код IL
в авто-реализованном наборе свойств. Проблема в том, что я могу получить ссылку на него с объекта TypeDefinition.Fields
, но когда я ввожу инструкцию ldfld
(после инструкции ldarg.0
) с этой ссылкой она заставляет приложение прерываться, а исключение CLR invalid program detected
. Я также попытался декомпилировать ILSpy
и получил исключение Mono.Cecil argument out of range exepction in get_Item(int32) method
. Так что, как будто я пытаюсь получить доступ к фоновому полю до его создания компилятором, но каким-то образом Mono.Cecil
может видеть его при загрузке сборки.Mono.Cecil авто-реализованное свойство accessing backing field
public class ILTesting
{
public int Counter { get; set; }
}
Это, как сеттер выглядит перед инъекцией:
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld int32 SyringeWpfTest.ILTesting::'<Counter>k__BackingField'
IL_0007: ret
Вот инъекции код:
var fieldName = "<" + property.Name + ">k__BackingField";
var fieldRef = ilTestType.Fields.Single(field => field.Name == fieldName);
var setterInstruction = property.SetMethod.Body.Instructions;
setterInstructions.Insert(0, Instruction.Create(OpCodes.Brfalse_S, setterInstructions.Last()));
setterInstructions.Insert(0, Instruction.Create(OpCodes.Ldloc_0));
setterInstructions.Insert(0, Instruction.Create(OpCodes.Stloc_0));
setterInstructions.Insert(0, Instruction.Create(OpCodes.Ceq));
setterInstructions.Insert(0, Instruction.Create(OpCodes.Ldc_I4_0));
setterInstructions.Insert(0, Instruction.Create(OpCodes.Ceq));
setterInstructions.Insert(0, Instruction.Create(OpCodes.Ldarg_1));
setterInstructions.Insert(0, Instruction.Create(OpCodes.Ldfld, reference));
setterInstructions.Insert(0, Instruction.Create(OpCodes.Ldarg_0));
setterInstructions.Insert(0, Instruction.Create(OpCodes.Nop));
И это IL я получаю:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld int32 SyringeWpfTest.ILTesting::'<Counter>k__BackingField'
IL_0007: ldarg.1
IL_0008: ceq
IL_000a: ldc.i4.0
IL_000b: ceq
IL_000d: stloc.0
IL_000e: ldloc.0
IL_000f: brfalse.s IL_001a
IL_0011: nop
IL_0012: ldarg.0
IL_0013: ldarg.1
IL_0014: stfld int32 SyringeWpfTest.ILTesting::'<Counter>k__BackingField'
IL_0019: nop
IL_001a: ret
Так инъекционный код не нарушался, ссылка на backi ng существует, но в IL
выглядит так, что не существует поля поддержки.