2009-11-10 115 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