C # 中的谓词是什么?

我刚刚学会使用谓词,刚刚学会如何写:

Predicate<int> pre = delegate(int a){ a %2 == 0 };

谓词将返回什么,以及它在编程时如何有用?

166179 次浏览

根据定义,谓词将始终返回一个布尔值。

Predicate<T> Func<T,bool>基本相同。

谓词在编程中非常有用。它们通常用于允许您在运行时提供逻辑,逻辑可以是简单的,也可以是复杂的。

例如,WPF 使用 Predicate<T>作为 ListView 的 ICollectionView 的过滤输入。这使您可以编写逻辑来返回布尔值,以确定是否应该在最终视图中包含特定的元素。逻辑可以非常简单(只需在对象上返回一个布尔值) ,也可以非常复杂,这完全取决于您。

在 C # 谓词中,只是返回布尔值的委托。当您搜索一组对象并想要某些特定的东西时,它们是有用的(以我的经验)。

我最近在使用第三方 Web 控件(比如 treeviews)时遇到了它们,所以当我需要在树中找到一个节点时,我使用。Find ()方法并传递一个谓词,该谓词将返回我要查找的特定节点。在您的示例中,如果‘ a’mod 2为0,则委托将返回 true。当然,当我在树视图中查找节点时,我会比较匹配节点的名称、文本和值属性。当委托找到匹配项时,它将返回我正在查找的特定节点。

Predicate<T>是一个函数结构,它提供了一种简便的方法来基本测试给定的 T对象是否存在真实情况。

例如,假设我有一个类:

class Person {
public string Name { get; set; }
public int Age { get; set; }
}

假设我有一个 List<Person> people我想知道名单上有没有叫奥斯卡的人。

如果没有使用 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岁的人?

使用 Predicate<Person>,我可以用很少的代码找到这些东西:

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);

注意,我说了很多 更少的代码,而不是很多 再快点。开发人员普遍存在的一个误解是,如果某个代码只占用一行,那么它的性能必须优于占用10行的代码。但是在幕后,接受 Predicate<T>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改为类似于 evenFinderisEven的类型——沿着这些代码行。那么上面的代码就清楚多了:

int firstEven = ints.Find(evenFinder);

下面的代码可以帮助您理解谓词的一些实际用法(与命名迭代器结合使用)。

namespace Predicate
{
class Person
{
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
foreach (Person person in OlderThan(18))
{
Console.WriteLine(person.Age);
}
}


static IEnumerable<Person> OlderThan(int age)
{
Predicate<Person> isOld = x => x.Age > age;
Person[] persons = { new Person { Age = 10 }, new Person { Age = 20 }, new Person { Age = 19 } };


foreach (Person person in persons)
if (isOld(person)) yield return person;
}
}
}