Это просто вопрос любопытства, который меня интересовал, если бы у кого-нибудь был хороший ответ:
Например, в библиотеке классов .NET Framework есть два следующих метода:
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
)
Почему они используют Func<TSource, bool>
вместо Predicate<TSource>
? Похоже, что Predicate<TSource>
используется только List<T>
и Array<T>
, в то время Func<TSource, bool>
как используется в значительной степени все Queryable
и Enumerable
методы и методы расширения ... что с этим?
Ответы:
Хотя
Predicate
было введено в то же время, чтоList<T>
иArray<T>
в .net 2.0, разныеFunc
иAction
варианты происходят из .net 3.5.Таким образом, эти
Func
предикаты используются главным образом для согласованности в операторах LINQ. По состоянию на .net 3.5, об использованииFunc<T>
иAction<T>
в Принципах :источник
Я думал об этом раньше. Мне нравится
Predicate<T>
делегат - это красиво и описательно. Однако вам необходимо учитывать перегрузкиWhere
:Это позволяет вам фильтровать на основе индекса записи. Это хорошо и последовательно, тогда как:
не будет
источник
Where
метод расширенияpredicate
. Хех = П.Конечно, настоящая причина использования
Func
вместо конкретного делегата заключается в том, что C # рассматривает отдельно объявленные делегаты как совершенно разные типы.Несмотря на то,
Func<int, bool>
иPredicate<int>
оба имеют одинаковые аргументов и возвращаемых типов, они не являются присваивание-совместимыми. Поэтому, если бы каждая библиотека объявила свой собственный тип делегата для каждого шаблона делегата, эти библиотеки не смогут взаимодействовать, если пользователь не вставит «соединяющие» делегаты для выполнения преобразований.Призывая всех использовать Func, Microsoft надеется, что это облегчит проблему несовместимых типов делегатов. Все делегаты будут хорошо играть вместе, потому что они просто будут сопоставлены на основе их параметров / типов возврата.
Это не решает все проблемы, потому что
Func
(иAction
) не может иметьout
илиref
параметры, но они используются реже.Обновление: в комментариях Свиш говорит:
Да, если ваша программа только назначает методы для делегатов, как в первой строке моей
Main
функции. Компилятор автоматически генерирует код для нового объекта делегата, который пересылается в метод. Таким образом, в моейMain
функции я мог изменитьx1
тип,ExceptionHandler2
не вызывая проблем.Однако во второй строке я пытаюсь назначить первый делегат другому делегату. Даже если предположить, что 2-й тип делегата имеет одинаковые параметры и возвращаемые типы, компилятор выдает ошибку
CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'
.Может быть, это прояснит это:
Мой метод
IsNegative
является вполне хорошей вещью , чтобы назначить наp
иf
переменные, до тех пор , как я делаю это непосредственно. Но тогда я не могу присвоить одну из этих переменных другой.источник
Func<T, bool>
илиPredicate<T>
вместо того , тип , выведенный компилятором.Совет (в 3.5 и выше) заключается в использовании
Action<...>
иFunc<...>
- для «почему?» - одним из преимуществ является то, что «Predicate<T>
» имеет смысл только в том случае, если вы знаете, что означает «предикат» - в противном случае вам нужно взглянуть на объект-браузер (и т. д.), чтобы найти подпись.Обратно
Func<T,bool>
следует стандартному образцу; Я могу сразу сказать, что это функция, которая принимаетT
и возвращаетbool
- не нужно понимать никакой терминологии - просто примените мой тест на истинность.Для «предиката» это могло бы быть нормально, но я ценю попытку стандартизировать. Это также позволяет добиться большого паритета со связанными методами в этой области.
источник