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?

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

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

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.


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.