2010-08-18 16 views
7

J'ai besoin d'une méthode qui prend une Action (ou un Func), mais l'Action a un nombre de paramètres mélangé. Quelle est la manière la plus en avant et compact directement à mettre en œuvre ces surcharges:C# Action et surcharges des paramètres Func

public void Execute<T>(Action<T> action, T param) { 
    // TODO: Implement something like: 
    // Execute(action, param, null); 
} 

public void Execute<T1,T2>(Action<T1,T2> action, T1 param1, T2 param2) { 
    // TODO: Implement something like: 
    // Execute(action, param1, param2, null); 
} 

public void Execute<T1,T2,T3>(Action<T1,T2,T3> action, T1 param1, T2 param2, T3 param3) { 
    DoStuff(); 
    action(param1, param2, param3) 
    DoMoreStuff(); 
} 

// OR any other type of higher order function-solution 
public void Execute(Action action, params object[] parameters) { ... } // ??? 

Le contenu des méthodes sont exactement les mêmes, à l'exception de l'exécution de l'action et de ses paramètres.

Si possible, n'utilisez aucune fonctionnalité spécifique à C# 4.0 pour résoudre ce problème.

Répondre

8

Le contenu des méthodes sont exactement les mêmes, sauf pour l'exécution de l'action et ses paramètres.

qui crie à l'utilisation d'un higher order function, mais puisque vous avez déjà paramétrés tous les bits qui changent (exécution de l'action et de ses paramètres) vous êtes déjà là. Désolé, il semble que vous deviez implémenter ces surcharges manuellement.

Le chaînage à l'aide de null ne fonctionnera pas car les délégués passés ne correspondent pas. Ce que vous pouvez faire est envelopper l'action passée/func dans un lambda pour écailler arguments supplémentaires:

public void Execute(Action<T> action, T param) { 
    Execute((a, _) => action(a) , param, null); 
} 

public void Execute(Action<T1, T2> action, T1 param1, T2 param2) { 
    Execute((a, b, _) => action(a, b) , param1, param2, null); 
} 

public void Execute(Action<T1, T2, T3> action, T1 param1, T2 param2, T3 param3) { 
    DoStuff(); 
    action(param1, param2, param3) 
    DoMoreStuff(); 
} 
+0

N'hésitez pas à fournir également une fonction-fonction d'ordre supérieur. –

+0

@Seb: Concernant la fonction d'ordre supérieur: Vous êtes déjà là en paramétrant votre action. –

5

Ceci est en fait la meilleure approche (en gardant à point de l'esprit Johannes que vous auriez pu aussi utiliser une plus fonction de commande), car c'est le type le plus convivial (les délégués seront automatiquement mis en correspondance avec le nombre correct et les types d'arguments) et ne nécessite pas d'appels gênants DynamicInvoke.

Votre dernière définition de méthode est cependant problématique. De par sa nature même, un Action n'accepte aucun paramètre, donc il ne va pas jouer avec un argument params object[]. Si vous voulez une surcharge finale qui accepte un nombre variable d'arguments, je partirais avec DynamicInvoke après tout, pour cet appel de méthode:

public void Execute(Delegate action, params object[] parameters) 
{ 
    DoStuff(); 
    action.DynamicInvoke(parameters); 
    DoMoreStuff(); 
} 

Mais développiez ce que Johannes disait, je pense qu'il était essentiellement obtenir quelque chose comme ceci:

public Action<T1, T2, T3> CreateAction<T1, T2, T3>(Action action) 
{ 
    return (T1 x, T2 y, T3 z) => action(); 
} 

public Action<T1, T2, T3> CreateAction<T1, T2, T3>(Action<T1> action, T1 arg) 
{ 
    return (T1 x, T2 y, T3 z) => action(arg); 
} 

Et ainsi de suite - en d'autres termes, ce que vous avez déjà fait, mais dans un contexte général afin que le code est réutilisable dans d'autres endroits.