C# LINQ詳解(一)


原文標題:How does it work in C#?-Part 3 (C# LINQ in detail),作者:Mohammand A Rahman.

 

目錄 

LINQ 基礎 

擴展方法-幕后的工作 

擴展方法列表 

Where and Select 

All 

Average 

Concat 

Contains 

Count 

DefaultIfEmpty 

Distinct 

ElementAt 

Empty 

Except 

First 

FirstOrDefault 

Union 

Intersect 

Last 

LastOrDefault 

LongCount 

Max 

Min 

OfType 

Range 

Repeat 

Reverse 

Single 

Skip 

SkipWhile 

Sum 

ThenBy 

ToArray 

ToDictionary 

ToList 

Zip 

LINQ基礎介紹 

         .NET,任何數據結構都是由在mscorlib.dllSystem.Collections.Generic命名空間下的Ienumerable<T>接口得到的. 映射可以訪問所有的定義在System.Core.dllSystem.Linq命名空間下的枚舉類.這個枚舉類是定義在System.Core.dllSystem.Linq命名空間下的一個靜態非可繼承類.這個枚舉類的定義如下: 

.class public abstract auto ansi sealed beforefieldinit System.Linq.Enumerable extends [mscorlib]System.Object 

這個靜態枚舉類是對Ienumerable<T>接口中不同擴展方法的一個封裝.例如下面的例子: 

public static bool Contains<TSource>( 

    this IEnumerable<TSource> source, TSource value) 

{ /* code removed*/} 

public static int Count<TSource>( 

    this IEnumerable<TSource> source)  

{ /* code removed*/} 

public static IEnumerable<TSource> Distinct<TSource>( 

    this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)  

{ /* code removed*/} 

// and many more 

擴展方法介紹 

Where and Select 

Where Select是兩個定義在Ienumerable<TSource>接口中非常重要的方法.它們的定義如下: 

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

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

所以任何來源於Ienumerable<TSource>接口的數據結構都能訪問這個方法,例如List<T>.List<T>類實現了Ienumerable<T>接口,它的定義如下: 

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, Ienumerable 

那么來讓我們看一個關於WhereSelect的例子. 

 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<string> numbers = new List<string>()  
24 
25             {  
26 
27                 "One", "Two", "Three", "Four",  
28 
29                 "Five", "Six", "Seven"  
30 
31             }; 
32 
33  
34 
35             var numbersLengthThree = 
36 
37                 numbers.Where(x => x.Length == 3).Select(x => x).ToList(); 
38 
39  
40 
41             numbersLengthThree.ForEach(x => Console.WriteLine(x)); 
42 
43         } 
44 
45     } 
46 
47 } 

上面的代碼會產生一個string類型的列表(列表中是數字)存儲在List<string>,上面的程序會找出在這些項中字符總數是3的並且將結果存儲到另外一個新的列表中.最后在控制台中打印出這些數字.這個程序輸出的結果如下: 

One 

Two 

Six 

讓我們做一個研究去找出它是如何工作的.在上面的例子中最重要的代碼是numbers.Where(x => x.Length == 3).Select(x => x).ToList().下邊的圖表會為我們解釋整個的執行過程. 

通過上面的圖表我們可以知道CLR伴隨着MulticastDelegate實例(持有着關於<Main>b_1方法的信息)將數字列表作為輸入參數傳遞到Where方法,其中<Main>b_1創建於匿名函數(x=>x.Length==3).通過Where方法它會返回一個WhereListIterator<string>迭代器的實例,這個實例將會作為輸入參數傳遞到Select子句中,伴隨着另外一個MulticastDelegate實例(持有着關於<Main>b_2方法的信息),<Main>b_2通過匿名方法(x=>x)創建。Select方法將根據輸入內容實例化相關的迭代器。在這種情況下,它會實例化出WhereSelectListIterator<string,string>迭代器。這個迭代器將作為輸入參數傳遞到ToList()方法中。此方法最終通過循環遍歷對原始列表進行處理並得到一個基於過濾條件的新列表。 

 

All 

這個方法確定是否所有元素序列都滿足某種條件,如果每一個元素都可以滿足設定的特殊條件或者它是空,則方法返回true,否則返回false。方法定義如下: 

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

 

這個方法被用在判斷是否一個元素序列滿足某種條件。序列中的每一個元素都會經過判斷。在下面的程序中,我創建了一個包含OneTwoThree等項目的List<string>實例,下面的程序將找出在這個序列中是否包含不少於3個字符的元素。 

 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<string> numbers = new List<string>()  
24 
25             {  
26 
27                 "One", "Two", "Three", "Four",  
28 
29                 "Five", "Six", "Seven"  
30 
31             }; 
32 
33  
34 
35             if (numbers.All<string>(x => x.Length >= 3)) 
36 
37                 Console.WriteLine("All numbers have at least three characters."); 
38 
39         } 
40 
41     } 
42 
43 } 

 

上面的程序將會輸出:All numbers have at least three characters. 

因為All方法都將匹配序列中的元素對於指定的條件是否有效。它的工作原理如下圖: 

圖像

從上面的圖表我們可以知道CLR會通過數字列表作為輸入參數傳遞到All()中,伴隨着MulticasDelegate類的實例(這個實例通過匿名函數(x=>x.Length>=3)來創建)。在All()方法中,CLR將通過指定的條件找出序列中的每一個元素是否滿足條件。 

 

Any 

這個方法確定序列中的元素是否存在或者滿足某種特定的條件。方法定義如下: 

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

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

 

上面的兩個方法將會執行下面的情況: 

第一種重載會找出元素序列是否包含元素,第二種重載將會找出序列中是否有滿足條件的元素。我寫了一個小程序去解釋這兩種方法工作的細節。 

 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<string> numbers = new List<string>()  
24 
25             {  
26 
27                 "One", "Two", "Three", "Four",  
28 
29                 "Five", "Six", "Seven"  
30 
31             }; 
32 
33  
34 
35             if (numbers.Any<string>()) 
36 
37                 Console.WriteLine("The sequence contains item."); 
38 
39  
40 
41             if (numbers.Any<string>(x => x.Length >= 3)) 
42 
43                 Console.WriteLine("The sequence contains at least a item which has three or more characters"); 
44 
45  
46 
47         } 
48 
49     } 
50 
51 } 

 

上面的程序將會做如下輸出: 

The sequence contains item. 

The sequence contains at least a item which has three or more characters 

Press any key to continue . . . 

 

Average 

Average方法會計算在序列中的數字的平均值。這個方法的定義如下: 

public static double Average(this IEnumerable<int> source) 

public static decimal Average<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal> selector) 

 

下面是一個關於Average方法的列子: 

 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> numbers = new List<int>()  
24 
25             {  
26 
27                 1,2,3,4,5,6,7,8,9,10 
28 
29             }; 
30 
31  
32 
33             Console.WriteLine("Average of the numbers :{0}", numbers.Average()); 
34 
35  
36 
37             Console.WriteLine("Average of the original numbers x2 :{0}",  
38 
39                               numbers.Average((x => x * 2))); 
40 
41  
42 
43         } 
44 
45     } 
46 
47 } 

 

上面的程序將會做如下輸出: 

Average of the numbers :5.5 

Average of the original numbers x2 :11 

Press any key to continue . . . 

 

Concat 

這個方法的作用是連接(拼接)兩個序列.這個方法通過"延遲執行"(deferred execution)來執行.它的返回值是包含需要執行特定操作所有信息的迭代器類型的一種實例.C#,對象在調用它的GetEnumerator方法或者使用foreach語句時才會執行Concat方法. 

Concat<TSource>(Ienumerable<TSource>,Ienumerable<TSource>)方法不同於Union(),因為Concat<TSource>(Ienumerable<TSource>,Ienumerable<TSource>)方法會返回序列中所有的原始元素,Union則返回序列中不重復(獨一無二)的元素.方法定義如下: 

public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) 

 

下面的程序將告訴我們怎樣使用Concat方法. 

 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> listOne = new List<int>()  
24 
25             {  
26 
27                 1,2,3,4,5 
28 
29             }; 
30 
31  
32 
33             IList<int> listTwo = new List<int>()  
34 
35             {  
36 
37                 6,7,8,9,10 
38 
39             }; 
40 
41  
42 
43             var result = listOne.Concat(listTwo).ToList(); 
44 
45             result.ForEach(x=> Console.WriteLine(x)); 
46 
47  
48 
49  
50 
51         } 
52 
53     } 
54 
55 } 

 

上面的程序將會做如下輸出: 

1 

2 

3 

4 

5 

6 

7 

8 

9 

10 

Press any key to continue . . . 

Concat方法的工作原理如下圖所示: 

圖像

從上圖我們可以知道CLR通過將listOnelistTwo作為輸入參數傳遞到Concat方法中,並且從Concat方法中返回一個ConcatIterator實例作為輸出參數給這個方法的調用者.雖然這將通過延遲執行模式來執行,但是ToList()方法也會通過listOnelistTwoConcatIterator類的執行邏輯來開始處理並得到最終的集合。 

 

Contains 

這個方法用來判斷在一個序列(集合)中是否存在一個特殊的元素.這個方法有兩種重載方式,第一種是通過默認的比較器來判斷序列(集合)中是否有特殊的元素,另外一種是通過自定義IEqualityComparer<T>來確定序列(集合)中是否有特殊的元素.它們的方法定義如下: 

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) 

 

這個方法將會查找在集合中是否有一個特殊的值存在.為了解釋這個方法我寫了一個小程序: 

 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7  
 8 
 9 namespace Chapter_5 
10 
11 { 
12 
13     class Program 
14 
15     { 
16 
17         static void Main(string[] args) 
18 
19         { 
20 
21             IList<int> listOne = new List<int>()  
22 
23             {  
24 
25                 1,2,3,4,5 
26 
27             }; 
28 
29  
30 
31             var resultAsTrue = listOne.Contains(2); 
32 
33             var resultAsFalse = listOne.Contains(200); 
34 
35             Console.WriteLine("{0}\n{1}", resultAsTrue, resultAsFalse); 
36 
37         } 
38 
39     } 
40 
41 } 

 

上面的程序將會做如下輸出: 

True 

False 

Press any key to continue . . 

因此,在上述程序中當編譯器找到Contains方法的第一種重載方式,它會執行如下步驟:CLR會通過Contains方法在集合中查找一個特定的值.這種查找會有兩個方向,一種是如果輸入參數是一個空值(null value),(CLR)會在集合中循環遍歷是空值的項,如果其中一項是空值,就返回true,反之返回false.另一種情況是當不是空值的時候,CLR會對集合中的項依次進行比較,根據匹配值返回一個布爾類型作為應答. 

Contains方法的一個近似代碼如下所示: 

 1 public bool Contains(T item) 
 2 
 3 { 
 4 
 5     if (item == null) 
 6 
 7     { 
 8 
 9         for (int j = 0; j < this._size; j++) 
10 
11         { 
12 
13             if (this._items[j] == null) 
14 
15             { 
16 
17                 return true; 
18 
19             } 
20 
21         } 
22 
23         return false; 
24 
25     } 
26 
27  
28 
29     EqualityComparer<T> comparer = EqualityComparer<T>.Default; 
30 
31     for (int i = 0; i < this._size; i++) 
32 
33     { 
34 
35         if (comparer.Equals(this._items[i], item)) 
36 
37         { 
38 
39             return true; 
40 
41         } 
42 
43     } 
44 
45     return false; 
46 
47 } 

 

 

Count 

Count方法將返回序列(集合)中元素的個數.這個方法的定義如下: 

public static int Count<TSource>(this IEnumerable<TSource> source) 

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

 

上面的兩個重載方法將會做如下操作.第一種重載直接返回序列(集合)中元素的個數,第二種重載返回一個數字,表示在序列(集合)中有多少元素滿足指定的條件。 

Count方法將找出在集合中一共有多少個項.例如在下面的程序中我創建了一個string類型的集合,我用Count()來找出在這個集合里有多少項以及有多少項是超過3個字符的. 

 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<string> listOne = new List<string>()  
24 
25             {  
26 
27                 "One","Two","Three" 
28 
29             }; 
30 
31  
32 
33             var result = listOne.Count(); 
34 
35  
36 
37             var fourOrMoreCharacters = listOne.Count(item => item.Length > 3); 
38 
39             Console.WriteLine("{0}\n{1}", result,fourOrMoreCharacters); 
40 
41         } 
42 
43     } 
44 
45 } 

 

上面的程序會做如下輸出: 

3 

1 

Press any key to continue . . . 

在這個例子中我使用了Count方法的兩種重載方式. 

 

DefaultIfEmpty 

這個方法會返回一個IEnumerable<T>類型的元素或者當序列(集合)為空事放回一個默認的單例集合.這個方法的定義如下: 

public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source) 

public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source, TSource defaultValue) 

 

上面的兩種重載方式將會這樣做:第一種重載將返回指定的元素序列(集合)或者當序列(集合)為空的情況下返回一個單例集合中類型參數的默認值.第二種重載將返回指定的元素序列(集合)或者在序列(集合)為空的情況下返回一個單例集合中特定的值. 

這個方法可以用在一個不含有任何項的列表(集合)並且如果我們在這個列表中使用這個方法,它將返回缺省值.讓我們看看在下面的程序中如何使用DefaultIfEmpty方法. 

 1 using System.Collections; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7  
 8 
 9 namespace Chapter_5 
10 
11 { 
12 
13     class Program 
14 
15     { 
16 
17         static void Main(string[] args) 
18 
19         { 
20 
21  
22 
23             IList<Person> persons = new List<Person>(); 
24 
25             IList<int> numbers = new List<int>(); 
26 
27             IList<string> names = new List<string>(); 
28 
29  
30 
31             var defaultPersons = persons.DefaultIfEmpty(); 
32 
33  
34 
35             var defaultNumbers = numbers.DefaultIfEmpty().ToList(); 
36 
37  
38 
39             var defaultNames = names.DefaultIfEmpty(); 
40 
41         } 
42 
43     } 
44 
45  
46 
47     class Person 
48 
49     { 
50 
51         public string Name 
52 
53         { 
54 
55             get; 
56 
57             set; 
58 
59         } 
60 
61  
62 
63         public string Address 
64 
65         { 
66 
67             get; 
68 
69             set; 
70 
71         } 
72 
73  
74 
75         public int Age 
76 
77         { 
78 
79             get; 
80 
81             set; 
82 
83         } 
84 
85     } 
86 
87 } 

 

在上面的程序中我聲明了personnumbersnames三個集合,分別是Personintstring類型。這三個集合不包含任何項,它們的Count屬性將會返回0.當我使用DefaultIfEmpty方法在任意一個集合上時,CLR會做如下步驟去執行。首先CLR會復制一份集合到DefaultIfEmpty方法,從這個方法中,CLR會返回一個包含defaultvalue和源值的DefaultIfEmptyIterator<TSource>迭代器的實例。The defaultvalue property will contain the default value of the type of list and source will be the original list. CLR會把DefaultIfEmptyItereator傳遞到ToList()方法中,它會通過把DefaultIfEmptyItereator作為輸入參數調用集合類,在這個類中,CLR將遍歷原始列表(集合)並處理結果。 

圖像

DefaultIfEmptyTterator相近的代碼如下: 

 1 private static IEnumerable<TSource> DefaultIfEmptyIterator<TSource>(IEnumerable<TSource> source, TSource defaultValue) 
 2 
 3 { 
 4 
 5     using (IEnumerator<TSource> iteratorVariable0 = source.GetEnumerator()) 
 6 
 7     { 
 8 
 9         if (iteratorVariable0.MoveNext()) 
10 
11             do 
12 
13             { 
14 
15                 yield return iteratorVariable0.Current; 
16 
17             } 
18 
19             while (iteratorVariable0.MoveNext()); 
20 
21         else 
22 
23             yield return defaultValue; 
24 
25     } 
26 
27 } 

 

 

Distinct 

這個方法將從序列(集合)中返回去重復(Distinct)元素。這個方法的定義是: 

public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source) 

public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer) 

 

這個方法有兩種重載方式,第一種重載通過默認比較器從序列(集合)中返回去重復的元素。第二種重載通過使用自定義IEquaityComparer<T>從序列(集合)中返回去重復的元素。 

這個方法將會從列表(集合)中返回同一的項。如果我們有一個包含重復項的列表(集合),那么這個方法將會過濾掉重復的項並返回一個只包含單一值的新列表(集合)。我們來看下面的程序。 

 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> numbers = new List<int>() 
24 
25             { 
26 
27                 1,1,1,2,2,2,3,3,3 
28 
29             }; 
30 
31  
32 
33             var distinctedNumbers = numbers.Distinct().ToList(); 
34 
35             distinctedNumbers.ForEach(x=>Console.WriteLine(x)); 
36 
37         } 
38 
39     } 
40 
41 } 

 

程序會輸出: 

1 

2 

3 

Press any key to continue . . . 

當上面程序運行的時候,它會只產生{123},下面的圖表描述了Distinct方法如何工作。 

圖像

要執行Distinct方法,CLR會這樣做:第一,CLR會拷貝一份原始列表(集合)並作為輸入參數傳遞到Distinct方法並且在內部調用Distinct<TSource>方法,這將返回一個DistinctIterator<TSource>類的實例,但是這個迭代器因為“延遲執行”不會執行(要執行DistinctIterator迭代器,我們需要調用ToList()方法或做ForEach)。第二,從ToList()方法,CLR會通過在第一步中創建的DistinctIterator作為輸入參數調用列表(集合)類。這個列表(集合)類將會循環遍歷DistinctIterator的實例。在DistinctIterator中的迭代邏輯會創建一個新的Set<TSource>實例並循環遍歷原始列表然后將重復的項添加到先前創建的Set<TSource>實例中。內部的這個Set<TSource>類會使用AddFind方法從給定的序列(集合)中把項添加到內部的數組中直到數組里沒有了重復項。這步操作會在CLR到達列表(集合)最后是才會停止並得到一個去重復的列表(集合)。因此,Distinct方法在list中會這樣執行: 

 1 private static IEnumerable<TSource> DistinctIterator<TSource>( 
 2 
 3     IEnumerable<TSource> source, IEqualityComparer<TSource> comparer) 
 4 
 5 { 
 6 
 7     Set<TSource> iteratorVariable0 = new Set<TSource>(comparer); 
 8 
 9     foreach (TSource iteratorVariable1 in source) 
10 
11     { 
12 
13         if (iteratorVariable0.Add(iteratorVariable1)) 
14 
15         { 
16 
17             yield return iteratorVariable1; 
18 
19         } 
20 
21     } 
22 
23 } 

 

 

ElementAt 

在序列(集合),這個方法返回一個特定索引的一個元素.這個方法的定義是: 

public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index) 

public static TSource ElementAtOrDefault<TSource>(this IEnumerable<TSource> source, int index) 

 

在下面的示例中使用了Ienumerable<TSource>ElementAt方法. 

 1 using System; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7   
 8 
 9 namespace Chapter_5 
10 
11 { 
12 
13     class Program 
14 
15     { 
16 
17         static void Main(string[] args) 
18 
19         { 
20 
21             IList<string> numbers = new List<string>() 
22 
23             { 
24 
25                 "One","Two","Three" 
26 
27             }; 
28 
29   
30 
31             var elementAt = numbers.ElementAt(1); 
32 
33   
34 
35             Console.WriteLine(elementAt); 
36 
37         } 
38 
39     } 
40 
41 } 

 

這個程序創建了一個包含OneTwoThree元素的數字集合。在這個數字列表中我嘗試去訪問在位置1處的元素並將結果存儲到elementAt變量中,然后在控制台輸出.這個程序的輸出結果是: 

Two 

Press any key to continue . . . 

 

Empty 

Empty返回一個指定類型參數的空Ienumerable<T>. 

方法定義如下: 

public static IEnumerable<TResult> Empty<TResult>() 

 

下面的示例說明了Empty方法的用法. 

 1 using System; 
 2 
 3 using System.Linq; 
 4 
 5  
 6 
 7 namespace Chapter_5 
 8 
 9 { 
10 
11     class Program 
12 
13     { 
14 
15         static void Main(string[] args) 
16 
17         { 
18 
19             var emptyList = Enumerable.Empty<int>(); 
20 
21  
22 
23             Console.WriteLine(emptyList.Count()); 
24 
25         } 
26 
27     } 
28 
29 } 

 

在上面的代碼中我用Empty()方法創建了一個int類型的空集合,程序會做如下輸出: 

0 

Press any key to continue . . . 

 

Except 

Except方法可以用在從一個集合中刪除一個項集合.它放回一個由兩個序列產生的集合差.方法定義是: 

1 public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) 
2 
3 public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) 

 

第一種重載是利用默認的比較器生成兩個序列的集合差.第二種重載是利用IEQualityComparer<T>生成兩個序列的集合差.Except方法可以用在從一個集合中刪除一個項集合.比如,我有個由{1,2,3,4,5,6,7}組成的集合A和由{1,2,3}組成的集合B,A 除了(except) B 將會輸出{4,5,6,7},下面的程序說明了Except的用法. 

 1 using System.Collections; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7 using System; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> firstNumbers = new List<int>() 
24 
25             { 
26 
27                 1,2,3,4,5,6,7 
28 
29             }; 
30 
31             IList<int> secondNumbers = new List<int>() 
32 
33             { 
34 
35                 1,2,3 
36 
37             }; 
38 
39  
40 
41             var result = firstNumbers.Except(secondNumbers).ToList(); 
42 
43             result.ForEach(x => Console.WriteLine(x)); 
44 
45         } 
46 
47     } 
48 
49 } 

 

程序將會輸出: 

4 

5 

6 

7 

Press any key to continue . . . 

當上面的程序執行的時候會產生{4,5,6,7},下面的圖表展示了Except方法是如何工作的. 

圖像

 

 

First 

這個方法會返回序列中的第一個元素.方法定義是: 

public static TSource First<TSource>(this IEnumerable<TSource> source) 

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

 

第一種重載將找出在序列中的第一個元素.第二種重載將根據條件找出第一個元素.我寫了一個小程序去解釋First方法的執行步驟. 

 1 using System.Collections; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7 using System; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> numbers = new List<int>() 
24 
25             { 
26 
27                 1,2,3,4,5,6,7 
28 
29             }; 
30 
31  
32 
33             var firstItem = numbers.First(); 
34 
35             var firstItemBasedOnConditions = numbers.First(item => item > 3); 
36 
37  
38 
39             Console.WriteLine("{0}\n{1}", 
40 
41                 firstItem, 
42 
43                 firstItemBasedOnConditions 
44 
45                 ); 
46 
47         } 
48 
49     } 
50 
51 } 

 

程序將會輸出: 

1 

4 

Press any key to continue . . . 

 

FirstOrDefault 

它返回序列中第一個元素或者當沒有元素未被找到時放回默認值.這個方法是FirstDefault的綜合,這里不再敘述. 

 

Union 

這個方法將會Union(並集)兩個序列(集合).例如,我們有兩個集合,A={1,2,3,4,5,6,7}B={5,6,7,8,9},並集AB則返回{1,2,3,4,5,6,7,8,9}..NET,它將連接兩個列表(集合)並生成一個新列表(集合). 

public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) 

public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) 

 

下面的程序說明了Union的用法. 

 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> firstList = new List<int>()  
24 
25             {  
26 
27                 1,2,3,4 
28 
29             }; 
30 
31  
32 
33             IList<int> secondList = new List<int>()  
34 
35             {  
36 
37                7,9,3,4,5,6,7 
38 
39             }; 
40 
41  
42 
43             var result = firstList.Union(secondList); 
44 
45             result.ToList().ForEach(x => Console.WriteLine(x)); 
46 
47         } 
48 
49     } 
50 
51 } 

 

程序將會輸出: 

1 

2 

3 

4 

7 

9 

5 

6 

Press any key to continue . . . 

 

 

Intersect 

它將產生兩個序列的交集.方法定義是: 

public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) 

public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first,  

              Enumerable<TSource> second,IEqualityComparer<TSource> comparer) 

 

第一種重載將會利用默認平等比較器來創建兩個序列的交集,第二種重載是利用IEqualityComparet<T>比較器去比較值然后產生兩個序列的交集.它產生兩個序列的交集.這個交集將會包含在兩個列表中相同的元素.例如,如果我們有一個A列表{1,2,3,4,5}B列表{4,5},取兩者交集之后就會生成{4,5}. 

圖像

看下面的程序 

 1 using System; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7   
 8 
 9 namespace Chapter_5 
10 
11 { 
12 
13     class Program 
14 
15     { 
16 
17         static void Main(string[] args) 
18 
19         { 
20 
21             IList<int> listA = new List<int>() { 1, 2, 3, 4, 5 }; 
22 
23             IList<int> listB = new List<int>() { 4, 5 }; 
24 
25   
26 
27             var intersectResult = listA.Intersect(listB); 
28 
29   
30 
31             intersectResult.ToList().ForEach(x => Console.Write("{0}\t",x)); 
32 
33             Console.WriteLine(); 
34 
35         } 
36 
37     } 
38 
39 } 

 

程序會輸出: 

4       5 

Press any key to continue . . . 

 

 

Last 

它返回序列中最后一個元素.方法定義是: 

public static TSource Last<TSource>(this IEnumerable<TSource> source) 

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

 

第一種重載將會找出在序列中最后一個元素,第二種重載將根據條件找出最后一個元素.我寫了一個程序去解釋這個方法如何使用: 

 1 using System; 
 2 
 3 using System.Collections.Generic; 
 4 
 5 using System.Linq; 
 6 
 7 using System.Text; 
 8 
 9 using System.Threading.Tasks; 
10 
11  
12 
13 namespace Chapter1 
14 
15 { 
16 
17     class Program 
18 
19     { 
20 
21         static void Main(string[] args) 
22 
23         { 
24 
25             IList<int> numbers = new List<int>() 
26 
27             { 
28 
29                 1,2,3,4,5,6,7 
30 
31             }; 
32 
33  
34 
35             var lastItem = numbers.Last(); 
36 
37  
38 
39             var lastItemBasedOnConditions = numbers.Last(item => item > 3); 
40 
41  
42 
43             Console.WriteLine(lastItem); 
44 
45             Console.WriteLine(lastItemBasedOnConditions); 
46 
47         } 
48 
49     } 
50 
51 } 

 

將會輸出: 

7 

7 

Press any key to continue . . . 

 

 

LastOrDefault 

它返回序列中最后一個元素或者當沒有元素未被找到時放回默認值.這個方法是LastDefault的綜合,這里不再敘述. 

 

LongCount 

它會返回一個Int64去表示序列中元素的個數,方法定義是: 

public static long LongCount<TSource>(this IEnumerable<TSource> source) 

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

 

第一種重載放回一個Int64,表示在序列中一共有多少個元素.第二種重載是根據條件放回一個Int64,表示在條件范圍內一共有多少個元素. 

讓我們做一個例子: 

View Code
 1 using System; 
 2 
 3 using System.Collections; 
 4 
 5 using System.Collections.Generic; 
 6 
 7 using System.Linq; 
 8 
 9  
10 
11 namespace Chapter_5 
12 
13 { 
14 
15     class Program 
16 
17     { 
18 
19         static void Main(string[] args) 
20 
21         { 
22 
23             IList<int> firstList = new List<int>()  
24 
25             {  
26 
27                 1,2,3,4 
28 
29             }; 
30 
31  
32 
33             Console.WriteLine(firstList.LongCount()); 
34 
35         } 
36 
37     } 
38 
39 } 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM