簡體   English   中英

使用Reflection.Emit奇怪的參數序列

[英]Strange parameter sequence using Reflection.Emit

我最近一直在看Reflection.Emit。 我寫了一個簡單的程序,生成了一個DynamicMethod,該方法簡單地調用了另一個具有相同參數的方法

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

我不太清楚為什么...如果你們知道使用Reflection.Emit有任何好的資源,您能指出我的方向嗎。 我一直在使用Reflector和Emit AddIn。

干杯

羅漢

您遇到的問題是您正在調用動態方法,而不是靜態方法。 您生成的方法沒有對Program類的實例的引用。

還要注意,您正在將6個參數方法的7個參數壓入堆棧。 第一個參數應該是您要在其上調用該方法的對象的引用。

您看到的怪異行為可能是由於沒有索引6的參數,並且它回繞到了參數數組的開頭。

請參閱VS幫助中的“如何:定義和執行動態方法”。

您可以通過在方法調用中接受對象參數或使其靜態化來使其工作:

公共委托void TestHandler(對象實例,整數a,整數b,整數c,整數d,整數e,整數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);
}

要使其正常工作,您應該

  1. 使Question成為static方法
  2. 注釋gen.Emit(OpCodes.Ldarg_S,6);
  3. 相應地修改MethodInfo method1 = ...

一種“氣味”是,停止在Question方法上的調試時,您無法評估this引用。 這不應該用於實例方法... ;-)

編輯:操作。 我剛剛看到了羅伯特·瓦格納(Robert Wagner)的答案,這比我的解釋要好得多。 准備取消我的帖子,如果需要... :-)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM