2009-11-10 120 views
135

我很新的使用谓词和刚学会写:什么是C#中的谓词?

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

会有什么谓语回报,它是如何有用的编程是什么时候?

+13

这里是我的博士辣椒,谓词和安全功能的文章:http://blogs.msdn.com/ericlippert/archive/2008/08/19/tasty-beverages.aspx – 2009-11-10 21:30:21

+2

@ 0A0D:我觉得如果问题不是特定于该版本,那么标记问题“.net-2.0”是一个糟糕的主意。只需标记“.net”。 – 2010-08-28 00:04:11

+0

@John:同意。它原来有2.0,所以我只是将.net和2.0合并到.net-2.0中。 – 2010-08-28 00:19:52

回答

380

Predicate<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! 
} 

这是好的,但后来我们说,我想检查是否有名为“露丝”的人?还是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); 

通知我说了很多更少的代码,不是很多更快。开发人员常见的误解是,如果某件事情需要一条线,那么它的表现要比需要十条线的事情要好。但在幕后,采用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); 
+30

+1!到目前为止,页面上最清晰的答案。 – 2009-11-10 19:15:50

+3

+1:写得很好。我只想添加单行表单MSDN:“表示定义一组标准并确定指定对象是否符合这些标准的方法” – 2009-11-10 19:26:03

+0

令人惊叹。也解答了这个问题。 – 2009-11-10 19:27:27

34

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

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

谓词在编程中非常有用。它们通常用于允许您在运行时提供逻辑,可以根据需要尽可能简单或复杂。

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

+0

只是可惜他们不是:) – leppie 2009-11-10 18:55:28

+7

代表在编程中很有用。坦率地说,我发现Predicate这个名字非常无益,因为这个问题明显证明了这一点。如果你真的想描述一个谓词,你会命名它Filter 。 – ChaosPandion 2009-11-10 19:00:14

+1

不是什么? [15个字符] – 2009-11-10 19:00:21

11

在C#中谓词只是代表返回布尔值的代表。当你搜索对象集合并想要特定的东西时,它们是有用的(以我的经验)。

我最近在使用第三方网页控件(如treeviews)时遇到了他们,所以当我需要在树中查找节点时,我使用.Find()方法并传递一个将返回特定节点我正在寻找。在你的例子中,如果'a'mod 2是0,委托将返回true。当然,当我在树形视图中查找节点时,我会比较它的名称,文本和值属性以进行匹配。当委托人发现匹配时,它返回我正在寻找的特定节点。

13

下面的代码可以帮助你了解一些现实世界中使用的谓词(名为迭代器相结合)。

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; 
     } 
    } 
} 
+1

或者,您可以不用foreach/yield循环来“返回persons.FindAll(isOld);”。 – 2017-08-13 02:14:34