To tylko pytanie z ciekawości zastanawiałem się, czy ktoś miał dobrą odpowiedź na:
W bibliotece klas .NET Framework mamy na przykład te dwie metody:
public static IQueryable<TSource> Where<TSource>(
this IQueryable<TSource> source,
Expression<Func<TSource, bool>> predicate
)
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
)
Dlaczego używają Func<TSource, bool>
zamiast Predicate<TSource>
? Wydaje się, że Predicate<TSource>
jest używany tylko przez List<T>
i Array<T>
, gdy Func<TSource, bool>
jest używany przez prawie wszystkich Queryable
, a Enumerable
metody i sposoby przedłużania ... o co chodzi z tym?
Odpowiedzi:
Chociaż
Predicate
został wprowadzony w tym samym czasie,List<T>
a takżeArray<T>
w .net 2.0, różneFunc
iAction
warianty pochodzą z .net 3.5.Więc te
Func
predykaty są używane głównie dla spójności w operatorach LINQ. Począwszy od .NET 3.5 na temat używaniaFunc<T>
iAction<T>
ze stanów wytycznych :źródło
Zastanawiałem się nad tym wcześniej. Lubię
Predicate<T>
delegata - jest miły i opisowy. Należy jednak wziąć pod uwagę przeciążeniaWhere
:To pozwala na filtrowanie również na podstawie indeksu pozycji. To miłe i konsekwentne, podczas gdy:
nie byłoby.
źródło
Where
metodzie rozszerzenia topredicate
. Heh = P.Z pewnością faktycznym powodem użycia
Func
zamiast konkretnego delegata jest to, że C # traktuje osobno zadeklarowanych delegatów jako zupełnie różne typy.Chociaż
Func<int, bool>
iPredicate<int>
oba mają identyczne typy argumentów i powrotne, nie są one kompatybilne zadanie. Jeśli więc każda biblioteka zadeklaruje własny typ delegata dla każdego wzorca delegowania, biblioteki te nie będą mogły współpracować, dopóki użytkownik nie wstawi „mostkujących” delegatów w celu wykonania konwersji.Zachęcając wszystkich do korzystania z Func, Microsoft ma nadzieję, że rozwiąże to problem niekompatybilnych typów delegatów. Wszyscy delegaci będą się dobrze bawić razem, ponieważ zostaną dopasowani na podstawie ich parametrów / typów powrotu.
Nie rozwiązuje wszystkich problemów, ponieważ
Func
(iAction
) nie mogą mieć parametrówout
aniref
parametrów, ale są one rzadziej używane.Aktualizacja: w komentarzach Svish mówi:
Tak, o ile twój program przypisuje metody tylko delegatom, tak jak w pierwszym wierszu mojej
Main
funkcji. Kompilator po cichu generuje kod do nowego obiektu delegowanego, który przekazuje dalej metodę. Tak więc w mojejMain
funkcji mogłem zmienićx1
się na typExceptionHandler2
bez powodowania problemu.Jednak w drugim wierszu próbuję przypisać pierwszego delegata innemu delegatowi. Nawet sądząc, że drugi typ delegata ma dokładnie ten sam typ parametru i zwracany typ, kompilator podaje błąd
CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'
.Może to wyjaśni:
Moja metoda
IsNegative
jest całkowicie dobra do przypisania do zmiennychp
if
, o ile robię to bezpośrednio. Ale wtedy nie mogę przypisać jednej z tych zmiennych do drugiej.źródło
Func<T, bool>
czyPredicate<T>
zamiast typ wywieść przez kompilator.Porada (w wersji 3.5 i wyższej) polega na użyciu
Action<...>
iFunc<...>
- dla „dlaczego?” - jedną zaletą jest to, że „Predicate<T>
” ma sens tylko wtedy, gdy wiesz, co oznacza „orzecznik” - w przeciwnym razie musisz spojrzeć na przeglądarkę obiektów (itp.), aby znaleźć sygnatutę.I odwrotnie,
Func<T,bool>
podąża za standardowym wzorem; Mogę od razu powiedzieć, że jest to funkcja, która przyjmujeT
i zwracabool
- nie trzeba rozumieć żadnej terminologii - po prostu zastosuj mój test prawdy.W przypadku „predykatu” mogło to być w porządku, ale doceniam próbę standaryzacji. Pozwala to również na wiele parzystości z powiązanymi metodami w tym obszarze.
źródło