其他分享
首页 > 其他分享> > 发射操作可能会破坏运行时的稳定性,以增加字段

发射操作可能会破坏运行时的稳定性,以增加字段

作者:互联网

我用相同的标题搜索了很多问题,但没有找到适合我的答案.

所以我只是想增加我的类实例的字段:

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