2017-10-17 95 views
1

給定一種方法,我需要將其轉換爲委託,以便我可以在其上調用.DynamicInvoke()。因此,舉例來說,給定方法Foo,我不能做new Action<dynamic, dynamic>(Foo),因爲我實際上並不知道Foo必須有2個參數。如何將具有未知數量參數的方法轉換爲System.Delegate?

那麼如何在不知道參數的情況下將方法轉換爲Delegate

此問題與代碼生成有關。我想寫生成C#代碼的方法,把它歸結爲:

void GenerateCall(string method, params string[] args) { 
    Console.WriteLine($"Delegate del_{method} = {/*Convert method to delegate here*/};"); 
    Console.WriteLine($"del_{method}.DynamicInvoke({string.Join(", ", args)});"); 
} 

分配的方法給一個變量是我在做什麼重要,Console.WriteLine($"{method}({string.Join(", ", args)})")不夠好。

+0

你試過'params'?你必須創建你自己的代表。我不是100%確定這是否是重複的https://stackoverflow.com/a/1136510/495455,但它非常非常相似。 –

+0

@JeremyThompson不幸的是,這不是我的問題。這並不是說該方法有一個'params'參數,但我不知道它有什麼樣的參數。 – Pavel

+0

你能提供[mcve]嗎?沒關係,如果它不起作用... –

回答

1

研究這個有點後,我發現,Expression類有會自動選擇合適的Func<...>Action<...>委託類型爲你,甚至在運行時創建新的自定義委託類型的方法,如果沒有匹配(即你具有比內置委託類型中可用參數更多的參數)。

用這種方法,你的問題的其餘部分對我來說似乎相對簡單。下面是如何使用Expression.GetDelegateType()才能獲得相應的委託類型,並從隨後可用於調用使用所提供的參數的方法,適當的委託實例創建一個例子:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Program program = new Program(); 

     InvokeMethod(null, typeof(Program), "M1", "foo"); 
     InvokeMethod(null, typeof(Program), "M2", 17, "bar"); 
     InvokeMethod(program, typeof(Program), "M3", false); 
    } 

    static void M1(string text) 
    { 
     WriteLine($"M1: {text}"); 
    } 

    static void M2(int i, string text) 
    { 
     WriteLine($"M2: {i}, {text}"); 
    } 

    void M3(bool f) 
    { 
     WriteLine($"M3: {f}"); 
    } 

    static void InvokeMethod(object instance, Type type, string methodName, params object[] args) 
    { 
     Delegate d = CreateDelegate(instance, type, methodName); 

     d.DynamicInvoke(args); 
    } 

    static Delegate CreateDelegate(object instance, Type type, string methodName) 
    { 
     MethodInfo mi = type.GetMethod(methodName, 
      BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); 
     Type delegateType = Expression.GetDelegateType(mi.GetParameters() 
      .Select(pi => pi.ParameterType) 
      .Concat(new[] { mi.ReturnType }).ToArray()); 

     return Delegate.CreateDelegate(delegateType, instance, mi); 
    } 
} 
+0

非常感謝你!這正是我需要的。 – Pavel

相關問題