Ответ
Predicate<T> — это встроенный делегат в пространстве имён System, представляющий метод, который определяет, удовлетворяет ли объект типа T некоторому условию. Его сигнатура: bool Predicate<in T>(T obj).
Основное назначение: Передача логики проверки (условия) в методы, которые выполняют поиск, фильтрацию или проверку элементов в коллекциях. Это классический пример шаблона "Стратегия" (Strategy).
Практическое использование:
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 1. Определение предиката как лямбда-выражения
Predicate<int> isEven = x => x % 2 == 0;
// 2. Использование в методах класса List<T>
List<int> evenNumbers = numbers.FindAll(isEven); // Результат: [2, 4, 6, 8, 10]
// 3. Поиск первого элемента, удовлетворяющего условию
int firstEven = numbers.Find(isEven); // Результат: 2
// 4. Проверка существования элемента
bool hasEven = numbers.Exists(isEven); // Результат: true
// 5. Удаление всех элементов, удовлетворяющих условию
int removedCount = numbers.RemoveAll(isEven); // numbers теперь [1, 3, 5, 7, 9]
Сравнение с Func<T, bool>:
Оба делегата функционально эквивалентны. Predicate<T> появился в .NET Framework 2.0 и исторически используется в API коллекций (List<T>, Array). Func<T, bool> — часть более общей системы делегатов, введённой в .NET Framework 3.5.
// Predicate<T>
Predicate<int> predicate = x => x > 5;
// Func<T, bool>
Func<int, bool> func = x => x > 5;
// Оба можно использовать, но для List<T>.FindAll требуется Predicate
var result1 = numbers.FindAll(predicate); // OK
// var result2 = numbers.FindAll(func); // Ошибка компиляции
// Решение: явное приведение или обёртка
var result2 = numbers.FindAll(new Predicate<int>(func)); // OK
Рекомендация: В новом коде для унификации часто предпочитают использовать Func<T, bool>, особенно в LINQ-запросах и собственных API. Однако при работе со старыми методами коллекций (FindAll, RemoveAll и т.д.) необходимо использовать Predicate<T>.