Func <T> bez parametru out

167

Czy mogę przekazać metodę z parametrem out jako Func?

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

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

Func potrzebuje typu, więc out nie zostanie tam skompilowany, a wywołanie listFunction wymaga int i nie pozwoli na wyjście.

Czy jest na to sposób?

blu
źródło

Odpowiedzi:

228

refi outnie są częścią definicji parametru typu, więc nie można używać wbudowanego Funcdelegata do przekazywania refi outargumentów. Oczywiście, jeśli chcesz, możesz zadeklarować własnego delegata:

delegate V MyDelegate<T,U,V>(T input, out U output);
Mehrdad Afshari
źródło
7
W C # 4 (2010) i późniejszych (nie został opublikowany, gdy pisałeś swoją odpowiedź) można oznaczyć Tjako kontrawariantne i Vjako kowariantne. Jednak ponieważ parametr ( output) typu Ujest przekazywany przez odwołanie , Unie może być oznaczony jako współ- lub kontrawariantny i musi pozostać „niezmienny”. Rozważ więc, public delegate V MyDelegate<in T, U, out V>(T input, out U output);czy używasz C # 4 lub nowszego.
Jeppe Stig Nielsen
24

Dlaczego nie utworzyć klasy, która będzie zawierać wyniki?

public class Result
{
     public IList<Foo> List { get; set; }
     public Int32 Count { get; set; }
}
ChaosPandion
źródło
13

FuncRodzina delegatów (lub Actiondla tej sprawy) są tylko typy proste delegowanie jak deklarowane

//.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)

itp. Delegaci jako tacy mogą mieć parametry out / ref, więc w twoim przypadku jest to tylko kwestia samodzielnej implementacji, jak wskazały inne odpowiedzi. Jeśli chodzi o to, dlaczego Microsoft nie zapakował tego domyślnie, pomyśl o samej liczbie kombinacji, których wymagałby.

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)

tylko dla dwóch parametrów. Nawet się nie dotknęliśmy ref. W rzeczywistości byłoby to kłopotliwe i mylące dla programistów.

nawfal
źródło
2
Należy pamiętać, że przeciążanie funkcji C # nie może rozróżnić między delegate TResult Func<T1, T2, TResult>(T1 obj, T2 obj)i delegate TResult Func<T1, T2, TResult>(out T1 obj, T2 obj). Więc oprócz liczby przeciążeń nazwa symbolu jest kolejnym powodem, dla którego firma Microsoft nie mogła dodać tych przeciążeń Func.
Kasper van den Berg
Czy ktoś może skierować mnie do artykułu MSDN na temat powyższych delegatów?
Su Llewellyn
@SuLlewellyn Nie mogłem znaleźć oryginalnego artykułu msdn, ale możesz spróbować: docs.microsoft.com/en-us/dotnet/api/… , docs.microsoft.com/en-us/dotnet/api/…
nawfal
0

Możesz umieścić to w lambda / delegate / function / method, która ujawnia właściwy interfejs i nazywa się FindForBar, ale podejrzewam, że FindForBar liczy się jako parametr out jako powód, więc musisz być pewien, że wyrzucenie tej informacji było ok / bezpieczny / pożądany / miał właściwe wyniki (musiałbyś być tego pewien, nawet jeśli możesz po prostu przekazać bezpośrednio w FindForBar).

Logan Capaldo
źródło