2015-08-19 2 views
4

Я использую 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 выглядит так, что не существует поля поддержки.

ответ

1

Проблема решена! Это не собственность, это был способ IL. Я сделал полное свойство с кодом:

private int _counter; 

public int Counter 
{ 
    get { return _counter; } 
    set 
    { 
      if (_counter != value) 
      { 
       _counter = value; 
       NotifyUI(); 
      } 
     } 
} 

Я открыл собрание в ILSpy и IL кода был так же, как я введен в автоматические Реализуемых собственности. Но тогда я декомпилированы что IL, чтобы увидеть, что C# код выглядит после decompileing, и код выглядел так:

private int _counter; 

public int Counter 
{ 
    get { return _counter; } 
    set 
    { 
      bool flag = _counter != value; //THIS THING MADE MY LIFE SO HARD FOR A FEW DAYS! 
      if (flag) 
      { 
       _counter = value; 
       NotifyUI(); 
      } 
     } 
} 

Таким образом, проблема отсутствует локальная переменная на методы стека кадра. После того, как я вставил локальную переменную в метод, все работает отлично.

myProperty.SetMethod.Body.Variables.Add(new VariableDefinition(assembly.MainModul.Import(typeof(bool))); 
Смежные вопросы