2010-08-18 17 views
7

Ho bisogno di un metodo che richiede un'azione (o un Func), ma l'azione ha un numero misto di parametri. Qual è il modo più semplice e compatto per implementare questi sovraccarichi:C# Operazione e sovraccarico dei parametri 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) { ... } // ??? 

Il contenuto dei metodi sono esattamente lo stesso, tranne per l'esecuzione dell'azione ed i suoi parametri.

Se possibile, non utilizzare alcuna funzionalità specifica di C# 4.0 per risolvere questo problema.

risposta

8

Il contenuto dei metodi sono esattamente lo stesso, tranne per l'esecuzione dell'azione e suoi parametri.

che urla per l'utilizzo di un higher order function, ma dal momento che già parametrizzato tutti i bit che stanno cambiando (esecuzione dell'azione e dei suoi parametri) si è già lì. Spiacenti, sembra che dovrai implementare questi sovraccarichi manualmente.

Il concatenamento tramite null non funziona poiché i delegati passati non corrispondono. Che cosa si potrebbe fare è avvolgere l'azione/func passata all'interno di una lambda a staccarsi argomenti aggiuntivi:

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

Non esitate a fornire anche una soluzione di ordine superiore. –

+0

@Seb: Per quanto riguarda la funzione di ordine superiore: ci sei già avendo parametrizzato la tua azione. –

5

Questo è in realtà l'approccio migliore (tenendo a punto la mente di Johannes che si potrebbe aver anche utilizzato un più alto funzione di ordine), in quanto è il più amichevole (i delegati saranno automaticamente abbinati al numero e ai tipi di argomenti corretti) e non richiede fastidiose chiamate DynamicInvoke.

L'ultima definizione di metodo è tuttavia problematica. Un Action per sua natura non accetta alcun parametro, quindi non funzionerà correttamente con un argomento params object[]. Se si desidera un sovraccarico di finale che accetta un numero variabile di argomenti, mi piacerebbe andare con DynamicInvoke dopo tutto, solo per questa chiamata di metodo:

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

Ma per espandere su quello che Johannes stava dicendo, penso che lui era fondamentalmente ottenere a qualcosa di simile:

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

E così via - in altre parole, quello che hai già fatto, ma in un contesto generale in modo che il codice è riutilizzabile in altri luoghi.

Problemi correlati