2017-07-19 59 views
1

我希望能夠將方法鏈接到所有類型的委託。我試圖用refelection.emit做到這一點,並將動態方法與delagate的佔用空間相鏈接,將其添加到委託中,並讓此動態方法使用所有參數調用常規函數。但我希望有一個easyer方式來做到這一點。鏈接一般方法委託

(我沒有包括reflection.emit代碼becouse是不是我想幫助,這仍然是一個原始試)

這是我想要得到結果的一個例子:

public class FooClass 
    { 
     public delegate string MyFirstDelegate(string input1, string input2); 
     public delegate int MySecondDelegate(int input1, string input2, short input3); 

     public static MyFirstDelegate firstDelegate = null; 
     public static MySecondDelegate SecondDelegate = null; 

     private static string FirstMethod(string input1, string input2) 
     { 
      return input1 + input2; 
     } 

     private static int SecondMethod(int input1, string input2, short input3) 
     { 
      return input1 + Convert.ToInt32(input2) + input3; 
     } 

     private static object ThirdMethod(params object[] inputs) 
     { 
      //do some magic and return result 
     } 

     public static void Main() 
     { 
      firstDelegate = FirstMethod; 
      SecondDelegate = SecondMethod; 

      string result = firstDelegate("1", "2"); 
      int result2 = SecondDelegate(1, "3", 3); 

      //obviously this does not work, but is there a way to link this method to the delegate? 
      firstDelegate = ThirdMethod;  
      SecondDelegate = ThirdMethod; 

      string result3 = firstDelegate("1", "2"); 
      int result4 = SecondDelegate(1, "3", 3); 
     } 
    } 

回答

0

要鏈接的方法來所有類型的委託,你可以讓helper方法使用Expression這樣的:

private static TTarget ConvertDelegate<TTarget>(MethodInfo source) 
{ 
    var targetMethod = typeof(TTarget).GetMethod("Invoke"); 
    var parameters = targetMethod.GetParameters().Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray(); 
    var methodCall = Expression.Call(source, Expression.NewArrayInit(typeof(object), parameters)); 
    var delegateExpression = Expression.Lambda<TTarget>(Expression.TypeAs(methodCall, targetMethod.ReturnType), parameters); 
    return delegateExpression.Compile(); 
} 

然後你可以使用它像這樣:

var methodInfo= typeof(FooClass).GetMethod(nameof(ThirdMethod), BindingFlags.NonPublic | BindingFlags.Static); 
firstDelegate = ConvertDelegate<MyFirstDelegate>(methodInfo); 

我還創建的helper方法從方法名稱得到MethodInfo

private static MethodInfo GetMethodInfo<T>(string methodName) 
{ 
    return typeof(T).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static); 
} 

private static TTarget ConvertDelegate<TTarget, TSource>(string sourceMethodName) 
{ 
    return ConvertDelegate<TTarget>(GetMethodInfo<TSource>(sourceMethodName)); 
} 

然後你可以使用它像這樣:

firstDelegate = ConvertDelegate<MyFirstDelegate, FooClass>(nameof(ThirdMethod)); 

不要forgett是ConvertDelegate會只有帶簽名object Name(object[] inputs)的包裝方法,並且如果您只需要包裝一種方法,則可以將某些本地值保存爲MethodInfo,並且不會以p每次參加。