c# - Mono.Cecil auto-implemented property accessing backing field -
i using mono.cecil inject il code in auto-implemented property setter. problem is, can reference typedefinition.fields object when inject ldfld instruction (after ldarg.0 instruction ofc) reference causes application break, , clr invalid program detected exception raised. tried decompile ilspy , got exception mono.cecil argument out of range exepction in get_item(int32) method. it's trying access backing field before it's created compiler, somehow mono.cecil can see when loads assembly.
public class iltesting { public int counter { get; set; } } this how setter looks before injection:
il_0000: ldarg.0 il_0001: ldarg.1 il_0002: stfld int32 syringewpftest.iltesting::'<counter>k__backingfield' il_0007: ret here injection code:
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)); and il get:
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 so injection code didn't break, reference backing field exists, in il looks there not backing field @ all.
problem solved! it's wasn't property, way il works. made full property code:
private int _counter; public int counter { { return _counter; } set { if (_counter != value) { _counter = value; notifyui(); } } } i opened assembly in ilspy , il code injected auto-implemented property. decompiled il see c# code looks after decompileing, , code looked like:
private int _counter; public int counter { { return _counter; } set { bool flag = _counter != value; //this thing made life hard few days! if (flag) { _counter = value; notifyui(); } } } so, problem missing local variable on methods stack frame. after inserted local variable in method, work perfect.
myproperty.setmethod.body.variables.add(new variabledefinition(assembly.mainmodul.import(typeof(bool)));
Comments
Post a Comment