iT邦幫忙

DAY 25
3

分享一些學習心得系列 第 25

LINQ自學筆記-語法應用-設定方法-Any、All、Contains

  • 分享至 

  • xImage
  •  

本文將為大家介紹 LINQ 設定方法中,Any、All、Contains 這三個標準查詢運算子。這三個運算子可以讓我們判斷資料是否存在或包含特定的項目。
自學筆記這系列是我自己學習的一些心得分享,歡迎指教。這系列的分享,會以 C# + 我比較熟的 Net 3.5 環境為主。
另外本系列預計至少會切成【打地基】和【語法應用】兩大部分做分享。打地基的部分,講的是 LINQ 的組成元素,這部分幾乎和 LINQ 無關,反而是 C# 2.0、C# 3.0 的一堆語言特性,例如:型別推斷、擴充方法、泛型、委派等等,不過都會把分享的範圍限制在和 LINQ 應用有直接相關功能。
PS. LINQ 自學筆記幾乎所有範例,都可直接複製到 LINQPad 4 上執行(大多是用 Statements 和 Program 模式)。因為它輕巧好用,功能強大,寫範例很方便,請大家自行到以下網址下載最新的 LINQPad:http://www.LINQpad.net/。
Any 運算子用來判斷序列中,是否至少有一個項目,或者是否有任何項目符合指定的條件。以下是兩個多載方法的簽名碼:

public static bool Any<TSource>( 
    this IEnumerable<TSource> source 
)
public static bool Any<TSource>( 
    this IEnumerable<TSource> source, 
    Func<TSource, bool> predicate 
)

第一個多載方法,不用傳入任何參數,可直接在來源序列上調用 Any 運算子,只要序列不是空的(至少有一個項目),就會回傳 true,反之回傳 false。請注意,若來源序列是 null,則執行時會拋回 ArgumentNullException 例外:

var list = new List<string>() {"ASUS","Acer","BenQ", "Toshiba","IBM","HP","Dell"}; 
var emptyList = new List<string>() {}; 
Console.WriteLine(list.Any()); 
Console.WriteLine(emptyList.Any());
/* 輸出:
True 
False
*/

上述程式碼定義了兩個字串清單做資料來源,list 清單有 7 個項目,emptyList 沒有任何項目,分別在兩個序列上調用 Any 運算子的第一個多載方法,得到輸出結果。

第二個多載方法則是可以讓我們傳入一個委派 predicate,自行決定序列中的項目要符合什麼樣的邏輯才為真(true):

var list = new List<string>() {"ASUS","Acer","BenQ", "Toshiba","IBM","HP","Dell"}; 
Console.WriteLine(list.Any (l => l == "Acer")); 
Console.WriteLine(list.Any (l => l.Length > 10)); 
/* 輸出:
True 
False 
*/

上述程式碼定義一個廠牌名稱的資料來源清單,然後用 Any 運算子第二個多載方法,定義兩個 LINQ 查詢。第一個查詢檢查序列中是否有 Acer 這個廠牌名稱,第二個查詢檢查序列中項目,是否有任何一個長度大於 10。

第二個要說明的主題是 All 運算子,用途是判斷來源序列中【所有】項目是否都符合設定的條件,所以它只有一個方法簽名:

public static bool All<TSource>( 
    this IEnumerable<TSource> source, 
    Func<TSource, bool> predicate 
)

All 運算子要求我們必須傳入一個委派 predicate,自行設定條件,然後來源序列中所有項目都必須符合才為真(true)。

我們可以比較一下和 Any 運算子的差異:Any 運算子第二個多載方法是判斷來源序列中是否有【任一個】項目符合指定條件,All 運算子則是判斷來源序列【所有】項目都必須符合條件才回傳 true。以下為 All 運算子的範例:

var list = new List<string>() {"ASUS","Acer","BenQ", "Toshiba", "Dell"}; 
Console.WriteLine(list.All(l => l.Length > 3)); 
Console.WriteLine(list.All(l => l.Contains("A")));
/* 輸出:
True 
False 
*/ 

上述程式碼建立一個字串清單,再定義兩個 LINQ 查詢,第一個是設定所有項目的長度是否都大於 3,第二個查詢則是檢查序列中所有項目是否都有包含 "A",並輸出兩個查詢的查詢結果。

All 運算子有一個特性請大家特別注意,如果來源序列是空的(沒有任何項目),則不管設定的條件為何,回傳都是真(true):

var emptyList = new List<string>() {};
Console.WriteLine(emptyList.All(l => l.Contains("A")));
/* 輸出:
True 
*/

但是來源序列若是 null,則會造成 ArgumentNullException 例外。

本文最後一個主題是 Contains 運算子,它用來判斷序列中是否包含指定的項目。請注意,.Net 3.5 的 LINQ to Entities、LINQ to SQL 完全不支援 Contains 運算子!但是在 .Net 4.0 版本,則支援第一個多載方法。以下是 Contains 運算子兩個多載方法:

public static bool Contains<TSource>( 
    this IEnumerable<TSource> source, 
    TSource value 
)
public static bool Contains<TSource>( 
    this IEnumerable<TSource> source, 
    TSource value, 
    IEqualityComparer<TSource> comparer 
)

兩個多載方法差別就是第一個方法使用型別(TSource)預設的相等比較子,第二個方法則是傳入自訂的 IEqualityComparer<TSource> 來判斷序列中是否包含指定項目:

var list = new List<string>() {"ASUS","Acer","BenQ", "Toshiba", "Dell"}; 
Console.WriteLine(list.Contains("Acer")); 
Console.WriteLine(list.Contains("A"));
/* 輸出:
True 
False 
*/

上述程式碼建立一個字串清單,再定義兩個 LINQ 查詢,第一個查詢用 Contains 運算子檢查序列中是否包含 "Acer" 這個字串,第二個查詢則是檢查是否包含 "A" 字串。第二個查詢主要是要突顯這裡的 IEnumerable<TSource>.Contains 運算子檢查是兩個物件必須完全相同,和 String.Contains 方法是不同的意思。是的,我在學習 LINQ 時,曾一度混淆過,所以特別 Highlight 一下。

Contains 運算子第二個多載方法可以讓我們自訂物件相等的判斷邏輯:

void Main() 
{ 
    var list = new List<string>() {"ASUS","Acer","BenQ", "Toshiba", "Dell"}; 
    var comparer = new IgnoreCaseSensitive(); 
    Console.WriteLine(list.Contains("asus")); 
    Console.WriteLine(list.Contains("asus", comparer)); 
} 
//自訂忽略大小寫的相等比較子 
public class IgnoreCaseSensitive : IEqualityComparer<string> 
{ 
    public bool Equals(string s1, string s2) 
    { 
        return (s1.ToUpper().Equals(s2.ToUpper())); 
    } 
    public int GetHashCode(string str) 
    { 
        return str.ToUpper().GetHashCode(); 
    } 
}
/* 輸出:
False 
True
*/ 

上述程式碼,我們建立一個字串清單,也建立一個實做 IEqualityComparer<string> 的類別,用以判斷兩個字串是否相等時,要忽略大小寫(程式邏輯是全部轉大寫再呼叫字串的 Equals 方法),然後設定兩個 LINQ 查詢,第一個查詢使用 Contain 運算子第一個多載方法,所以會使用字串的預設相等比較子,第二個查詢使用自訂的 IgnoreCaseSensitive 類別來做忽略大小寫的字串比較,然後輸出結果。

文章結束前,提醒大家,這三個運算子都是立即執行查詢的運算子,使用時請注意一下。


上一篇
LINQ自學筆記-語法應用-分頁方法-Take、Skip、TakeWhile、SkipWhile
下一篇
LINQ自學筆記-語法應用-設定方法-Range、Repeat、Empty、Distinct
系列文
分享一些學習心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言