代码之家  ›  专栏  ›  技术社区  ›  Rohan West

使用reflection.emit的奇怪参数序列

  •  1
  • Rohan West  · 技术社区  · 16 年前

    我一直在观察反射。最近发射。我编写了一个简单的程序,它生成一个dynamicmethod,Simple使用相同的参数调用另一个方法。

    class Program
    {
        static void Main(string[] args)
        {
            Program p = new Program();
            p.Test();
        }
    
        public delegate void TestHandler(int a, int b, int c, int d, int e, int f);
    
        public void Test()
        {
            DynamicMethod method = new DynamicMethod(string.Empty, typeof(void), new[] { typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, typeof(Program));
    
    
            MethodInfo method1 = typeof(Program).GetMethod("Question",BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,null,new Type[]{typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32)},null);
            MethodInfo method2 = typeof(MethodBase).GetMethod("GetCurrentMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null);
            MethodInfo method3 = typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Object) }, null);
    
            ILGenerator gen = method.GetILGenerator();
    
            gen.Emit(OpCodes.Nop);
            gen.Emit(OpCodes.Ldarg_S, 0);
            gen.Emit(OpCodes.Ldarg_S, 1);
            gen.Emit(OpCodes.Ldarg_S, 2);
            gen.Emit(OpCodes.Ldarg_S, 3);
            gen.Emit(OpCodes.Ldarg_S, 4);
            gen.Emit(OpCodes.Ldarg_S, 5);
            gen.Emit(OpCodes.Ldarg_S, 6);
            gen.Emit(OpCodes.Call, method1);
            gen.Emit(OpCodes.Nop);
            gen.Emit(OpCodes.Call, method2);
            gen.Emit(OpCodes.Call, method3);
            gen.Emit(OpCodes.Nop);
            gen.Emit(OpCodes.Ret);
    
            TestHandler handler = method.CreateDelegate(typeof(TestHandler)) as TestHandler;
            handler(1, 2, 3, 4, 5, 6);
        }
    
        public void Question(int a, int b, int c, int d, int e, int f)
        {
            Console.WriteLine("{0},{1},{2},{3},{4},{5}", a, b, c, d, e, f);
        }
    }
    

    当我运行这个例子时,我希望它输出1,2,3,4,5,6,但是,它输出2,3,4,5,6,1

    我不太确定为什么…如果你们知道使用反射的任何好资源,Emit能给我指出那个方向吗?我一直在使用反射镜和发射插件。

    干杯

    罗翰

    2 回复  |  直到 13 年前
        1
  •  5
  •   Robert Wagner    16 年前

    您遇到的问题是,您正在调用一个动态方法,而不是静态方法。生成的方法没有对程序类实例的引用。

    另外请注意,对于6参数方法,您正在将7个参数推送到堆栈中。 第一个参数应该是对正在调用方法的对象的引用。

    您所看到的奇怪行为可能是因为没有索引6的参数,并且它将返回到参数数组的开头。

    请参见vs帮助中的“如何:定义和执行动态方法”。

    您可以通过在方法调用中接受上的对象参数,或使其静态化来使其工作:

    公共委托void testhandler(对象实例,int a,int b,int c,int d,int e,int f);

    public void Test()
    {
        DynamicMethod method = new DynamicMethod(string.Empty, typeof(void), new[] { typeof(object), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, typeof(Program));
    
    
        MethodInfo method1 = typeof(Program).GetMethod("Question", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, null);
        MethodInfo method2 = typeof(MethodBase).GetMethod("GetCurrentMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null);
        MethodInfo method3 = typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Object) }, null);
    
        ILGenerator gen = method.GetILGenerator();
    
        gen.Emit(OpCodes.Nop);
        gen.Emit(OpCodes.Ldarg_S, 0);
        gen.Emit(OpCodes.Ldarg_S, 1);
        gen.Emit(OpCodes.Ldarg_S, 2);
        gen.Emit(OpCodes.Ldarg_S, 3);
        gen.Emit(OpCodes.Ldarg_S, 4);
        gen.Emit(OpCodes.Ldarg_S, 5);
        gen.Emit(OpCodes.Ldarg_S, 6);
        gen.Emit(OpCodes.Call, method1);
        gen.Emit(OpCodes.Nop);
        gen.Emit(OpCodes.Call, method2);
        gen.Emit(OpCodes.Call, method3);
        gen.Emit(OpCodes.Nop);
        gen.Emit(OpCodes.Ret);
    
        TestHandler handler = method.CreateDelegate(typeof(TestHandler)) as TestHandler;
        handler(this, 1, 2, 3, 4, 5, 6);
    }
    
    public void Question(int a, int b, int c, int d, int e, int f)
    {
        Console.WriteLine("{0},{1},{2},{3},{4},{5}", a, b, c, d, e, f);
    }
    
        2
  •  1
  •   Fabrizio C.    16 年前

    为了让它发挥作用,你应该

    1. 制作 Question static 方法
    2. 评论 gen.Emit(OpCodes.Ldarg_S,6);
    3. 修改 MethodInfo method1 = ... 因此

    其中一个“气味”是在 问题 方法无法评估 this 参考文献。这不应该用于实例方法…;-)

    编辑:操作。我刚刚看到罗伯特·瓦格纳的回答,这比我的解释好得多。准备好取消我的职位,如果需要…:-)