2017-07-19 101 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每次参加。