发送操作可能会使运行时不稳定以增加字段

时间:2014-02-01 09:48:24

标签: c# .net reflection code-generation reflection.emit

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

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

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

所以它似乎是相同的

1 个答案:

答案 0 :(得分:4)

Action不接受任何争论,但你ldarg一个。您可能需要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();
        }
    }

的变化:

  1. 将代表绑定到目标
  2. 指定参数类型(您告诉构建器没有参数)
  3. 启用私人访问