2009-08-15 15 views
134

Posso passare un metodo con un parametro out come Func?Func <T> con parametro out

public IList<Foo> FindForBar(string bar, out int count) { } 

// somewhere else 
public IList<T> Find(Func<string, int, List<T>> listFunction) { } 

Func ha bisogno di un tipo così fuori non verrà compilato lì, e chiamando listFunction richiede un int e non permetterà un fuori in.

C'è un modo per fare questo?

risposta

192

ref e out non sono parte della definizione del parametro di tipo quindi non è possibile utilizzare il built-in Func delegato di passare ref e out argomenti. Naturalmente, è possibile dichiarare il proprio delegato, se si desidera:

delegate V MyDelegate<T,U,V>(T input, out U output); 
+13

Nel caso in cui qualcun altro sia confuso come me, non è necessario * chiamare * il proprio delegato "Func" come quelli interni ... – Dunc

+0

@Dunc - Corretto. Sarei stato davvero confuso se non fosse stato per il tuo commento. –

+5

In C# 4 (2010) e versioni successive (non è stato rilasciato quando hai scritto la tua risposta) è possibile contrassegnare "T" come controvariante e "V" come covariante. Tuttavia, poiché un parametro ('output') di tipo' U' viene passato *** per riferimento ***, 'U' non può essere contrassegnato co- o controvariante e deve rimanere" invariante ". Quindi considera 'delegato pubblico V MyDelegate (input T, output U out);' se usi C# 4 o successivo. –

19

Perché non creare una classe per incapsulare i risultati?

public class Result 
{ 
    public IList<Foo> List { get; set; } 
    public Int32 Count { get; set; } 
} 
0

Si poteva avvolgerlo in un/funzione/metodo lambda/delegato che ha esposto l'interfaccia destra e chiamato FindForBar, ma ho il sospetto che FindForBar è considerato come un parametro out come una ragione, così avresti bisogno di assicurati che buttare via queste informazioni fosse ok/sicuro/desiderabile/avessi i risultati giusti (dovresti essere sicuro di questo anche se potresti passare direttamente in FindForBar).

9

La Func famiglia dei delegati (o Action per questo) non sono altro che semplici tipi delegato dichiarati come

//.NET 4 and above 
public delegate TResult Func<out TResult>() 
public delegate TResult Func<in T, out TResult>(T obj) 

//.NET 3.5 
public delegate TResult Func<T1, T2, TResult>(T1 obj1, T2 obj2) 
public delegate TResult Func<T1, T2, T3, TResult>(T1 obj1, T2 obj2, T3 obj3) 

ecc delegati in quanto tale può avere parametri out/ref, quindi nel tuo caso è solo una questione di implementazione personalizzata da te stesso come hanno sottolineato altre risposte. Per quanto riguarda il motivo per cui Microsoft non l'ha compresso per impostazione predefinita, pensa al numero di combinazioni che richiederebbe.

delegate TResult Func<T1, T2, TResult>(T1 obj1, T2 obj2) 
delegate TResult Func<T1, T2, TResult>(out T1 obj1, T2 obj2) 
delegate TResult Func<T1, T2, TResult>(T1 obj1, out T2 obj2) 
delegate TResult Func<T1, T2, TResult>(out T1 obj1, out T2 obj2) 

per soli due parametri. Non abbiamo nemmeno toccato ref. Sarebbe davvero ingombrante e confuso per gli sviluppatori.

+1

Si noti che l'overloading della funzione C# non può distinguere tra 'delegate TResult Func (T1 obj, T2 obj)' e 'delegate TResult Func (out T1 obj, T2 obj)'. Quindi oltre al numero di overload il nome del simbolo è un altro motivo per il quale Microsoft non ha potuto aggiungere questi overload di 'Func'. –

Problemi correlati