2017-07-19 5 views
1

Je veux pouvoir lier une méthode à tous les types de délégués. J'essaye de faire ceci avec refelection.emit et lie une méthode dynamique avec l'empreinte de la delagate, l'ajoute au délégué et laisse cette méthode dynamique appeler une fonction générale avec tous les paramètres. mais j'espère qu'il y a une manière plus facile de faire ceci.Liaison méthode générale pour déléguer

(je n'ai pas inclus le code reflection.emit becouse qui n'est pas ce que je veux aider, et qui est encore d'essayer brut)

Ceci est un exemple de résultat que je veux:

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); 
     } 
    } 

Répondre

0

pour lier la méthode à tous les types de délégués que vous pouvez faire en utilisant la méthode d'aide Expression comme ceci:

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(); 
} 

Ensuite, vous pouvez l'utiliser comme ceci:

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

J'ai aussi créé des méthodes d'aide pour obtenir MethodInfo du nom de la méthode:

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)); 
} 

Ensuite, vous pouvez l'utiliser comme ceci:

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

Ne pas forgett que ConvertDelegate sera seule méthode wrap avec la signature object Name(object[] inputs), et si vous avez besoin d'envelopper une seule méthode, vous pouvez enregistrer MethodInfo dans une certaine valeur locale et ne pas passer comme p arameter chaque fois.