发射操作可能会破坏运行时的稳定性,以增加字段
作者:互联网
我用相同的标题搜索了很多问题,但没有找到适合我的答案.
所以我只是想增加我的类实例的字段:
class EmitTest
{
private int _calls = 0;
public EmitTest()
{
var callsFieldInfo = GetType().GetField("_calls", BindingFlags.NonPublic | BindingFlags.Instance);
Debug.Assert(callsFieldInfo != null, "callsFieldInfo != null");
var dynMethod = new DynamicMethod(new Guid().ToString(), typeof(void), null);
var ilGenerator = dynMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Nop);
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Dup);
ilGenerator.Emit(OpCodes.Ldfld, callsFieldInfo);
ilGenerator.Emit(OpCodes.Ldc_I4_1);
ilGenerator.Emit(OpCodes.Add);
ilGenerator.Emit(OpCodes.Stfld, callsFieldInfo);
ilGenerator.Emit(OpCodes.Ret);
Action delg = (Action)dynMethod.CreateDelegate(typeof(Action));
delg();
}
}
...
static void Main(string[] args)
{
var test = new EmitTest();
}
为什么它不起作用?我猜它与maxstack和局部变量有关,但我确实不知道.
关于代码:确保我为另一个类编写和反编译了相同的代码,这是:
class Program
{
private int i = 0;
static void Main(string[] args)
{
var test = new EmitTest();
var prog = new Program();
prog.Foo();
}
private void Foo()
{
i++;
}
}
反编译:
.method private hidebysig instance void Foo() cil managed
{
// Размер кода: 16 (0x10)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: dup
IL_0003: ldfld int32 ConsoleApplication97.Program::i
IL_0008: ldc.i4.1
IL_0009: add
IL_000a: stfld int32 ConsoleApplication97.Program::i
IL_000f: ret
} // end of method Program::Foo
所以似乎是一样的
解决方法:
动作不带任何参数,但您必须带一个参数.您可能需要一个Action< EmitTest>.
与您在其中编辑的反编译代码的区别似乎在于,此方法是一个实例方法,它带有一个隐式this参数.
当您调用delg()时;您认为这将在哪个EmitTest实例上运行?您从未指定一个.
您可以使用带有目标的CreateDelegate的重载.或使用Action< EmitTest>.
这有效:
class EmitTest
{
private int _calls = 0;
public EmitTest()
{
var callsFieldInfo = GetType().GetField("_calls", BindingFlags.NonPublic | BindingFlags.Instance);
Debug.Assert(callsFieldInfo != null, "callsFieldInfo != null");
var dynMethod = new DynamicMethod(new Guid().ToString(), typeof(void), new[] { typeof(EmitTest) } /*added*/, true /*added*/);
var ilGenerator = dynMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Nop);
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Dup);
ilGenerator.Emit(OpCodes.Ldfld, callsFieldInfo);
ilGenerator.Emit(OpCodes.Ldc_I4_1);
ilGenerator.Emit(OpCodes.Add);
ilGenerator.Emit(OpCodes.Stfld, callsFieldInfo);
ilGenerator.Emit(OpCodes.Ret);
Action delg = (Action)dynMethod.CreateDelegate(typeof(Action), this /*added*/);
delg();
}
}
变化:
>将代表绑定到目标
>指定参数类型(您告诉构建器没有参数)
>启用私人访问
标签:reflection-emit,reflection,code-generation,c,net 来源: https://codeday.me/bug/20191029/1963810.html