Predicate<T> - это функциональная конструкция, обеспечивающая удобный способ тестирования, если что-то верно для данного объекта T.
Например, предположим, что у меня есть класс:
class Person {
public string Name { get; set; }
public int Age { get; set; }
}
Теперь скажем, что у меня есть
List<Person> people, и я хочу знать, если кто-нибудь назвал Oscar в списке.
Без использования
Predicate<Person> (или Linq, или любого из этого причудливого материала) я всегда мог бы выполнить это, выполнив следующее:
Person oscar = null;
foreach (Person person in people) {
if (person.Name == "Oscar") {
oscar = person;
break;
}
}
if (oscar != null) {
// Oscar exists!
}
Это хорошо, но потом скажите, я хочу проверить, есть ли человек по имени "Ruth"? Или человек, возраст которого составляет 17 лет?
Используя
, я могу найти эти вещи, используя код LOT less:
Predicate<Person> oscarFinder = (Person p) => { return p.Name == "Oscar"; };
Predicate<Person> ruthFinder = (Person p) => { return p.Name == "Ruth"; };
Predicate<Person> seventeenYearOldFinder = (Person p) => { return p.Age == 17; };
Person oscar = people.Find(oscarFinder);
Person ruth = people.Find(ruthFinder);
Person seventeenYearOld = people.Find(seventeenYearOldFinder);
Заметьте, я сказал намного меньше кода, но не намного быстрее. Общее заблуждение разработчиков заключается в том, что если что-то занимает одну строку, оно должно работать лучше, чем что-то, что занимает десять строк. Но за кулисами метод Find, который принимает
, просто перечисляет в конце концов. То же самое верно для многих функций Linq.
Итак, давайте взглянем на конкретный код в вашем вопросе:
Predicate<int> pre = delegate(int a){ return a % 2 == 0; };
Здесь мы имеем
Predicate<int> pre, который принимает int a и возвращает
a % 2 == 0. Это, по существу, тестирование четного числа. Это означает:
pre(1) == false;
pre(2) == true;
И так далее. Это также означает, что если у вас есть
List<int> ints, и вы хотите найти первое четное число, вы можете просто сделать это:
int firstEven = ints.Find(pre);
Конечно, как и любой другой тип, который вы можете использовать в коде, неплохо дать свои переменные описательные имена; поэтому я бы посоветовал изменить вышеуказанный pre на что-то вроде
evenFinder или
isEven - что-то вдоль этих строк. Затем приведенный выше код намного понятнее:
int firstEven = ints.Find(evenFinder);