В чем разница между Predicate и Func в C#?

«В чем разница между Predicate и Func в C#?» — вопрос из категории C# Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Оба делегата представляют метод, принимающий один аргумент типа T и возвращающий bool, но имеют разные цели и области применения.

Predicate

  • Специализированный делегат, созданный исключительно для проверки условий (предикатов).
  • Историческое использование: Широко применяется в устаревших API коллекций, таких как List<T>.Find, List<T>.FindAll, Array.Find. Его сигнатура ясно указывает на намерение — фильтрацию или поиск.
List<int> numbers = new() { 1, 2, 3, 4, 5 };
Predicate<int> isEvenPredicate = x => x % 2 == 0;
List<int> evenNumbers = numbers.FindAll(isEvenPredicate); // Работает со старыми методами

Func<T, bool>

  • Универсальный делегат из пространства имён System. Часть общего семейства Func<> (входные параметры + возвращаемый тип).
  • Современный стандарт: Является основным выбором для LINQ (Where, Any, First), асинхронных операций и любых других сценариев, где требуется функция, возвращающая bool.
List<int> numbers = new() { 1, 2, 3, 4, 5 };
Func<int, bool> isEvenFunc = x => x % 2 == 0;
IEnumerable<int> evenNumbers = numbers.Where(isEvenFunc); // Стандарт для LINQ

Практическое правило:

  • Используйте Func<T, bool> для нового кода, особенно с LINQ — это современный и универсальный подход.
  • Используйте Predicate<T> только при необходимости совместимости со старыми API (например, List<T>.FindAll) или если хотите явно подчеркнуть, что делегат является именно условием для проверки.

Важно: Лямбда-выражение x => x % 2 == 0 может быть неявно преобразовано в оба типа, поэтому часто выбор зависит от контекста вызова метода.