一、Where 操做符用於限定輸入集合中的元素,將符合條件的元素組織聲稱一個序列結果。
二、Select 操做符用於根據輸入序列中的元素建立相應的輸出序列中的元素,輸出序列中的元素類型能夠與輸入序列中的元素類型相同,也能夠不一樣。下面來看看Select方法的原型。
三、SelectMany 操做符用於根據輸入序列中的每個元素,在輸出序列中建立相應的零個或者多個元素,與Select操做符不一樣,Select操做符會根據輸入序列中的每個元素建立一個對應的輸出序列元素,而SelectMany操做符能夠建立多個。
四、Take 操做符用於從輸入序列中返回指定數量的元素,經常使用於分頁。
五、TakeWhile 操做符用於從輸入序列中返回指定數量且知足必定條件的元素。
六、Skip 操做符用於從輸入序列中跳過指定數量的元素,返回由序列中剩餘的元素所組成的新序列。
七、SkipWhile 操做符用於從輸入序列中跳過知足必定條件指定數量的元素,與TakeWhile操做符相似。
八、Concat 操做符用於鏈接兩個序列,生成一個新序列。
九、OrderBy 操做符用於對輸入序列中的元素進行排序,排序基於一個委託方法的返回值順序,排序過程完成後,會返回一個類型爲IOrderEnumerable<T>的集合對象。
十、OrderByDescending 操做符的功能與OrderBy操做符基本相同,兩者只是排序的方式不一樣OrderBy是順序排序,而OrderByDescending則是逆序排序。
十一、ThenBy 操做符能夠對一個類型爲IOrderedEnumerable<T>,(OrderBy和OrderByDesceding操做符的返回值類型)的序列再次按照特定的條件順序排序。
十二、ThenByDescending 操做符與ThenBy操做符很是相似,只是排序順序倒過來而已,不在過多闡述。
1三、Reverse 操做符用於生成一個與輸入序列中元素相同,但元素排列順序相反的新序列。
1四、Join 操做符相似於SQL語句中的Join語句用於鏈接多個表,Linq to OBJECT中Join操做符能夠用來鏈接兩個輸入序列。
1五、GroupJoin 操做符也用於鏈接兩個輸入序列,但與Join操做符不一樣稍有不一樣,Join操做符在列舉outer序列元素時,會將一個outer序列元素和其對應的inner序列元素做爲一組參數傳遞給委託resultSelector委託,這就意味着若是某一個outer序列元素有多個對應的inner序列元素,Join操做符將會分屢次將outer序列元素和每個對應的inner序列元素傳遞給委託resultSelector。使用GroupJoin操做符時,若是某一個outer序列元素有多個對應的inner序列元素,那麼這多個對應的inner序列元素會做用一個序列一次性傳遞給委託resultSelecotr,能夠針對此序列添加一些處理邏輯。
1六、GroupBy 操做符相似於SQL語言仲的Gruop By語句,這裏的GroupBy操做符用於將輸入序列中的元素進行分組。
1七、Distinct 操做符相似於SQL語句中的Distinct語句,這裏的Distinct操做符也用於去除一個序列中的重複元素。
1八、Union 操做符用於將兩個序列中的元素合併成一個新的序列,新序列將自動去除重複的元素。
1九、Intersect 操做符會將兩個輸入序列中的重複元素,即同時存在於兩個序列中的元素挑選出來,生成一個新的集合,也就是求交集。
20、Except 操做符能夠實現一種集合之間的減法運算,它返回兩個序列中存在於第一個序列但不存在於第二個序列的元素所組成的新序列。
2一、Cast 操做符用於將一個類型爲IEnumerable的集合對象轉換爲IEnumerable<T>類型的集合對象。也就是非泛型集合轉成泛型集合,由於在Linq to OBJECT中,絕大部分操做符都是針對IEnumerable<T>類型進行的擴展方法。所以對非泛型集合並不適用。
2二、OfType 操做符與Cast操做符相似,用於將類型爲IEnumerable的集合對象轉換爲IEnumerable<T>類型的集合對象。不一樣的是,Cast操做符會視圖將輸入序列中的全部元素轉換成類型爲T的對象,,若是有轉換失敗的元素存在Cast操做符將拋出一個異常;而OfType操做符僅會將可以成功轉換的元素進行轉換,並將這些結果添加到結果序列中去。與Cast操做符相比,OfType操做符更加安全。
2三、AsEnumerable 操做符能夠將一個類型爲IEnumerable<T>的輸入序列轉換成一個IEnumerable<T>的輸出序列,其主要用於將一個實現了IEnumerable<T>接口的對象轉換成一個標準的IEnumerable<T>接口對象。在Linq中、不一樣領域的Linq實現都有本身專屬的操做符。
2四、DefaultEmpty 操做符能夠用來爲一個空的輸入序列生成一個對應的含有默認元素的新序列。引用類型爲null,值類型爲相應的默認值。有些標準操做符在一個空的序列上調用時會拋出一個異常,而DefaultEmpty偏偏能夠解決這個問題。
2五、Range 操做符用於輔助生成一個整數序列。
2六、Repeat 操做符用於生成一個包含指定數量重複元素的序列。
2七、Empty 操做符用於生成一個包含指定類型元素的空序列。javascript
Linq to OBJECT是用於操做內存對象的LINQ編程接口,包含了大量的查詢操做符,針對內存中的集合對象進行操做。html
Linq to OBJECT的實現基於IEnumerable<T>、序列(sequences)以及標準查詢操做符(Standard Query Operators)等基本概念。標準查詢操做符本質上是一些擴展方法(Extension Methods),這些擴展方法定義在靜態類System.Linq.Enumerable中,其原型的第一個參數(帶this修飾符的參數)是IEnumerable<T>類型。因爲這些方法都是擴展方法,他們能夠在IEnumerable<T>的實例對象上直接調用。java
下面咱們來看下Linq to OBJECT上常用的一個Where擴展方法(這個在Linq中成爲操做符)的方法簽名git
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
從方法簽名中,咱們能獲得哪些信息呢?sql
一、這是一個擴展方法,擴展的是IEnumerable<T>接口。這就是說,實現了這個接口,或者繼承了這個接口的實例都可以使用此擴展方法。而IEnumerable<T>是比較底層的一個集合接口,不少集合 、集合接口和數組都實現或繼承了該接口。所以這些類和接口的實例都能用。數據庫
二、這是泛型方法,Where<T>代表,你能夠根據本身的類型傳入不一樣的類型參數。各類類型都可以使用。編程
三、方法參數是什麼東西呢?咱們轉到定義以後看到以下代碼:數組
[TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")] public delegate TResult Func<in T, out TResult>(T arg);
很明顯這是一個泛型委託。也就是說,咱們能夠用匿名方法或lambda表達式爲該泛型委託賦值。緩存
下面來演示下該方法的使用:安全
class Program { static void Main(string[] args) { List<int> listInt = new List<int>(); //List<T>類實現了IEnumerable<T>接口,所以它也可使用IEnumerable<T>的擴展方法 listInt.Add(1); listInt.Add(4); listInt.Add(5); listInt.Add(12); listInt.Add(15); //外部定義方法爲委託賦值 IEnumerable<int> IEnum1 = listInt.Where<int>(GetBiggerThanTen); foreach (int i in IEnum1) { Console.WriteLine(i); //輸出12 15 } Console.WriteLine("=============================="); //匿名方法爲委託賦值 IEnumerable<int> IEnum2 = listInt.Where<int>( delegate(int input) { if (input > 10) { return true; } return false; }); foreach (int i in IEnum2) { Console.WriteLine(i); //輸出12 15 } Console.WriteLine("=============================="); //Lambda表達式爲委託賦值 IEnumerable<int> IEnum3 = listInt.Where<int>(m => m>10); foreach (int i in IEnum3) { Console.WriteLine(i); //輸出12 15 } Console.WriteLine("=============================="); //以上3行代碼至關於複習了委託的相關知識,用不一樣的方式爲委託賦值,就是想說明參數是一個委託 //但若是真的像上面書寫那樣複雜,Linq就失去了它的意義,如下來看看最簡單的書寫形式 var Arr = listInt.Where(m => m>10); foreach (var i in Arr) { Console.WriteLine(i); //輸出12 15 一樣的效果 } Console.ReadKey(); } public static bool GetBiggerThanTen(int input) { if (input > 10) { return true; } return false; } }
一般咱們將鼠標放到擴展方面簽名上,看到智能代碼提示爲一個委託的時候,應該仔細解讀該委託。例如:
例如以上這個OrderBy這個操做符要求傳入一個委託,一般左邊是輸入,右邊是輸出(若是不肯定,能夠轉到定義肯定下)。例如此方法左邊輸入是string,右邊輸出是整數。注意只能提示會根據OBJECT的類型動態改變,所以給出的必定是最準確的提示。一般左邊都是集合中的元素的類型。右邊根據不一樣的方法變化(自己是泛型)。
案例以下:
static void Main(string[] args) { List<string> listInt = new List<string>(); //List<T>類實現了IEnumerable<T>接口,所以它也可使用IEnumerable<T>的擴展方法 listInt.Add("你好"); listInt.Add("嗎"); listInt.Add("我愛你"); listInt.Add("真的好想家了"); listInt.Add("哎"); IEnumerable<string> stringArr = listInt.OrderBy(m => m.Length); foreach (var item in stringArr) { Console.WriteLine(item); //輸出 嗎 哎 你好 我愛你 真的好想家了 } Console.ReadKey(); }
下面來講下Linq中的延時查詢(Deferred Query)特性。Linq的延時特性表示,在用的時候Linq纔去查。以下面這個例子。
static void Main(string[] args) { List<int> listInt = new List<int>(); //List<T>類實現了IEnumerable<T>接口,所以它也可使用IEnumerable<T>的擴展方法 listInt.Add(1); listInt.Add(2); listInt.Add(3); IEnumerable<int> IEnumInt = listInt.Select(m => m); //Linq查詢到的對象給IEnumInt集合賦值 foreach (int i in IEnumInt) { Console.Write(i + " "); //輸出 1 2 3 } Console.WriteLine(); listInt[0] = 4; listInt[1] = 5; listInt[2] = 6; foreach (int i in IEnumInt) //按道理說,咱們的程序沒有改變過IEnumerInt,理論上是不會更新IEnumerInt這個集合中的值 { Console.Write(i + " "); //但當改變原集合中的值再遍歷沒有更改過得IEnumInt時,輸出 4 5 6。注意IEnumInt這個集合沒有代碼改變過。 } //這就是Linq的延時查詢,在用的時候纔去查 Console.ReadKey(); }
固然,若是咱們不想要這類延時查詢,能夠在查詢表達式上調用一些轉換方法,如ToArray,ToList以及ToDictionary等方法來緩存結果數據。
static void Main(string[] args) { List<int> listInt = new List<int>(); listInt.Add(1); listInt.Add(2); listInt.Add(3); IEnumerable<int> IEnumInt = listInt.Select(m => m).ToArray(); //此處加個ToArray(),查詢當即執行,執行結果保存在IEnumerInt集合中 foreach (int i in IEnumInt) { Console.Write(i + " "); //輸出 1 2 3 } Console.WriteLine(); listInt[0] = 4; listInt[1] = 5; listInt[2] = 6; foreach (int i in IEnumInt) { Console.Write(i + " "); //輸出1 2 3 留意到1 2 3保存了起來,即便改變原集合再遍歷也不會改成最新的數據 } Console.ReadKey(); }
下面來介紹Linq提供的操做符。
1、延時標準查詢操做符。
一、Where操做符。
Where操做符用於限定輸入集合中的元素,將符合條件的元素組織聲稱一個序列結果。
Where方法原型有兩個,以下所示:
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);
擴展方法的概念就不說了,來看委託參數,此委託接受的方法爲,接受任何一個類型的參數,固然,這是根據你的泛型集合的類型肯定的,第二個參數表示輸出,即當每個元素調用賦給委託的方法返回值爲true時,就能添加該元素到結果序列對象中。
而第二個方法的委託參數多了個int參數,該參數表示元素的下標,下標從0開始,看示例:
static void Main(string[] args) { List<int> listInt = new List<int>(); listInt.Add(1); listInt.Add(5); listInt.Add(11); listInt.Add(20); listInt.Add(25); IEnumerable<int> IEInt = listInt.Where((m, p) => m > 10 && p > 2); //m表示輸入元素,p表示元素下標 foreach (int i in IEInt) //整個表達式的意思是,下標大於2,且元素值大於10 { Console.WriteLine(i); //輸出20 25 } Console.ReadKey(); }
二、Select操做符
Select操做符用於根據輸入序列中的元素建立相應的輸出序列中的元素,輸出序列中的元素類型能夠與輸入序列中的元素類型相同,也能夠不一樣。下面來看看Select方法的原型。
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector); public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);
Linq的東西大體相同,Select,Select的是元素的任意值或屬性。委託裏的參數兩個的話表示輸入和輸出,注意到都是泛型。而第一個int仍是表示下標。
Select方法的做用,很明顯,輸入是T,輸出是S。兩個都是泛型,輸入就確定是集合的元素了,輸出搞成泛型的做用就是讓你可以輸出任意類型的數據,例如元素的某個屬性啊等等,或自定義一個匿名類型。而Where的輸出參數設置成bool,目的在於它僅僅用於判斷,判斷哪一個元素複合條件,仍是返回元素。
class Program { static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(1, "關羽", 22); People p3 = new People(1, "劉備", 23); pList.Add(p1); pList.Add(p2); pList.Add(p3); IEnumerable<string> IEP = pList.Select(p => p.Name); //查詢的是元素的姓名屬性 foreach (string str in IEP) { Console.WriteLine(str); //輸出張飛 關羽 劉備 } //此處必須使用var,由於是匿名類型,沒法寫成IEnumerable<T>的形式 var newList = pList.Select((m, i) => new { index = i, m.Name }); //輸入元素與下標,返回一個新的匿名類型的集合 foreach (var item in newList) { Console.Write(item.Name); //輸出 張飛關羽劉備 } Console.ReadKey(); } } public class People { public People(int id, string name, int age) { this.Id = id; this.Name = name; this.Age = age; } public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } }
三、SelectMany操做符
SelectMany操做符用於根據輸入序列中的每個元素,在輸出序列中建立相應的零個或者多個元素,與Select操做符不一樣,Select操做符會根據輸入序列中的每個元素建立一個對應的輸出序列元素,而SelectMany操做符能夠建立多個。
下面來看下SelectMany操做符的方法原型:
public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector); public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TResult>> selector); public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector); public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector);
來看示例
static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(1, "關羽", 22); People p3 = new People(1, "劉備", 23); pList.Add(p1); pList.Add(p2); pList.Add(p3); var newList = pList.SelectMany(p => p.Name); //newList是一個包含全部p.Name的字符的集合IEnumerable<char> foreach (var item in newList) //Select是一個元素返回一個字符串,而SelectMany是一個元素返回多個字符 { Console.Write(item); //輸出 張飛關羽劉備 } Console.WriteLine(); var items = pList.SelectMany((p, i) => i < 2 ? p.Name.ToArray() : new char[] { }); //前兩個元素才轉成字符輸出 foreach (var i in items) { Console.Write(i); //輸出 張飛關羽 } Console.ReadKey(); }
//Person類與上面例子同樣,省略
Select與SelectMany的區別說明
Select()每一次遍歷,輸出的是T,而後將全部遍歷後獲得的T組合成一個IEnumerable<T>。
SelectMany()每遍歷一次,輸出的是IEnumerable<T>,而後合併成一個大的IEnumerable<T>。
假如舉個例子:
Select(p => p.Name); //遍歷IEnumerable<Person>,返回string類型的Name Selectmany(p => p.Name); //每次返回一個IEnumerable<char>,而後合併成一個大IEnumerable<char>。
一般來講,因爲selectmany強制每次遍歷返回IEnumerable<T>,所以通常用於嵌套的集合中,如:
List<List<int>> numbers = new List<List<int>>() { new List<int>{1,2,3}, new List<int>{4,5,6}, new List<int>{7,8,9} }; IEnumerable<int> result = numbers.SelectMany(collection => collection); //collection的類型是List<int>,要求返回IEnumerable<int> foreach(int i in result) { Console.WriteLine(i); }
輸出1,2,3,4,5,6,7,8,9
四、Take操做符
Take操做符用於從輸入序列中返回指定數量的元素,經常使用於分頁。
來看下Take操做符的方法原型。
public static IEnumerable<TSource> Take<TSource>(this IEnumerable<TSource> source, int count);
該方法只接受一個整數,表示要返回的結果的數量。
static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(1, "關羽", 22); People p3 = new People(1, "劉備", 23); pList.Add(p1); pList.Add(p2); pList.Add(p3); IEnumerable<People> newList = pList.Take(2); //只取前兩個結果 foreach (var item in newList) { Console.WriteLine(item.Name); //返回 張飛 關羽 } Console.ReadKey(); } //People類與上個同樣,省略
五、TakeWhile操做符
TakeWhile操做符用於從輸入序列中返回指定數量且知足必定條件的元素。
來看下TakeWhile的方法原型:
public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate); public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);
當TakeWhile操做符被調用時,會將source序列中的每個元素順序傳遞給委託predicate,只有那些使得predicate返回值爲true的元素纔會被添加到結果序列中。要特別注意的是,當TakeWhile操做符在查找過程當中,遇到第一個返回false的元素就會當即中止執行,跳出,無論後面還有沒有符合條件的元素,即便後面有符合條件的元素也不會要了。對於第二個擴展方法,委託裏面含有一個int類型的參數,該參數表明集合的下標,能夠依據此進行一些據下標操做的邏輯。
代碼示例:
static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(1, "關羽", 22); People p3 = new People(1, "劉備", 23); People p4 = new People(1, "孔明", 21); pList.Add(p1); pList.Add(p2); pList.Add(p3); pList.Add(p4); IEnumerable<People> newList = pList.TakeWhile(p => p.Age<23); //返回前兩個,注意TakeWhile操做符中,當遇到第一個返回false的元素就跳出執行 foreach (var item in newList) //無論後面還有沒有符合條件的元素 { Console.WriteLine(item.Name); //返回 張飛 關羽 //遇到劉備,返回false,則跳出,不會再執行到孔明。 } Console.WriteLine(); IEnumerable<People> newList1 = pList.TakeWhile((p,i) => p.Age<23 && i<1); //年齡小於23且下標小於1 foreach (People p in newList1) { Console.WriteLine(p.Name); //輸出張飛 } Console.ReadKey(); } //People類與上個同樣,省略
六、Skip操做符
Skip操做符用於從輸入序列中跳過指定數量的元素,返回由序列中剩餘的元素所組成的新序列。
來看下Skip的方法原型:
public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> source, int count);
能夠看到,該擴展方法只接受一個整形的參數,表示跳過的元素數量。
代碼示例:
static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(1, "關羽", 22); People p3 = new People(1, "劉備", 23); People p4 = new People(1, "孔明", 21); pList.Add(p1); pList.Add(p2); pList.Add(p3); pList.Add(p4); IEnumerable<People> newList = pList.Skip(2); //跳過前兩個 foreach (People p in newList) { Console.WriteLine(p.Name); //輸出 劉備 孔明 } Console.ReadKey(); } //People類與上個同樣,省略
七、SkipWhile操做符
SkipWhile操做符用於從輸入序列中跳過知足必定條件指定數量的元素,與TakeWhile操做符相似。
來看下SkipWhile操做符的方法原型:
public static IEnumerable<TSource> SkipWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate); public static IEnumerable<TSource> SkipWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);
當SkipWhile操做符被調用時,會將輸入序列中的元素走位參數傳遞給委託predicate,只要predicate的返回值爲true,該元素就會被跳過,繼續下一個元素,直到遇到一個使predicate返回值爲false的元素,此元素以及輸入序列中剩餘的元素將組合一個新的序列返回。注意後面的再也不判斷,直接添加到返回序列。
第二個擴展方法的委託裏的參數多了個int,仍是表明下標,能夠根據下標作一些邏輯處理。
static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(2, "關羽", 22); People p3 = new People(3, "劉備", 23); People p4 = new People(4, "孔明", 21); pList.Add(p1); pList.Add(p2); pList.Add(p3); pList.Add(p4); IEnumerable<People> newList = pList.SkipWhile(p => p.Age < 23); //跳過年齡小於23的,直到遇到劉備不在小於23,後面的再也不判斷,也添加到返回序列 foreach (People p in newList) { Console.WriteLine(p.Name); //輸出 劉備 孔明 } Console.WriteLine(); IEnumerable<People> newList1 = pList.SkipWhile((p, i) => p.Age<22 && i < 2); //跳過年齡小於22且下標小於2的,到關羽時不符合,所以關羽與後面的組合返回 foreach (People p in newList1) { Console.WriteLine(p.Name); //輸出 關羽 劉備 孔明 } Console.ReadKey(); } //People類與上個同樣,省略
八、Concat操做符
Concat操做符用於鏈接兩個序列,生成一個新序列。
來看下此方法的方法原型:
public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second);
第二個參數爲輸入一個新的集合,與調用集合鏈接,生成並返回一個新序列。代碼示例:
static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(2, "關羽", 22); People p3 = new People(3, "劉備", 23); People p4 = new People(4, "孔明", 21); pList.Add(p1); pList.Add(p2); pList.Add(p3); pList.Add(p4); List<People> pList1 = new List<People>(); People p5 = new People(5,"曹操",25); pList1.Add(p5); IEnumerable<People> newList = pList.Concat(pList1); foreach (var item in newList) { Console.WriteLine(item.Name); //輸出 張飛 關羽 劉備 孔明 曹操 } Console.ReadKey(); } //People類與上個同樣,省略
九、OrderBy操做符
OrderBy操做符用於對輸入序列中的元素進行排序,排序基於一個委託方法的返回值順序,排序過程完成後,會返回一個類型爲IOrderEnumerable<T>的集合對象。其中IOrdernumerable<T>接口繼承自IEnumerable<T>接口。下面來看看OrderBy的方法原型:
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector); public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer);
class Program { static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(2, "關羽", 22); People p3 = new People(3, "劉備", 23); People p4 = new People(4, "孔明", 21); pList.Add(p1); pList.Add(p2); pList.Add(p3); pList.Add(p4); IEnumerable<People> newList = pList.OrderBy(p => p.Age); foreach (var item in newList) { Console.WriteLine(item.Name); //輸出 張飛 孔明 關羽 劉備 (注意順序) } Console.WriteLine(); AgeComparer ac = new AgeComparer(); IEnumerable<People> newList1 = pList.OrderBy(p => p.Age, ac); foreach (var item in newList1) { Console.WriteLine(item.Name); //輸出 劉備 關羽 張飛 孔明 (注意順序) } Console.ReadKey(); } //People類與上個同樣,省略 } public class AgeComparer : IComparer<int> { public int Compare(int a1, int a2) { if (a1 > a2) { return (-1); //表示a1 > a2 } else if (a1 < a2) { return (1); //表示a1 < a2 } else { return (0); //表示a1=a2 } } }
十、OrderByDescending操做符
OrderByDescending操做符的功能與OrderBy操做符基本相同,兩者只是排序的方式不一樣OrderBy是順序排序,而OrderByDescending則是逆序排序。
來看方法原型
public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector); public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer);
與OrderBy同樣,只是排序順序倒過來了,來看示例:
static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(2, "關羽", 22); People p3 = new People(3, "劉備", 23); People p4 = new People(4, "孔明", 21); pList.Add(p1); pList.Add(p2); pList.Add(p3); pList.Add(p4); IEnumerable<People> newList = pList.OrderBy(p => p.Age); //順序 foreach (var item in newList) { Console.WriteLine(item.Name); //輸出 張飛 孔明 關羽 劉備 (注意順序) } IEnumerable<People> newList1 = pList.OrderByDescending(p => p.Age); //倒序 foreach (var item in newList1) { Console.WriteLine(item.Name); //輸出 劉備 關羽 張飛 孔明 (注意順序) } Console.ReadKey(); } //People類與上個同樣,省略
十一、ThenBy操做符
ThenBy操做符能夠對一個類型爲IOrderedEnumerable<T>,(OrderBy和OrderByDesceding操做符的返回值類型)的序列再次按照特定的條件順序排序。
下面來看ThenBy的方法原型:
public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector); public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer);
能夠看到此方法擴展的是IOrderedEnumerable<T>,所以ThenBy操做符長經常跟在OrderBy和OrderByDesceding以後。
static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(2, "關羽", 22); People p3 = new People(3, "劉備", 23); People p4 = new People(4, "孔明", 21); pList.Add(p1); pList.Add(p2); pList.Add(p3); pList.Add(p4); IEnumerable<People> newList = pList.OrderBy(p => p.Age).ThenByDescending(p => p.Id); //順序 foreach (var item in newList) { Console.WriteLine(item.Name); //沒用ThenBy本來是輸出 張飛 孔明 關羽 劉備 (注意順序),但 //可是本處在ThenByDescending以後,實際輸出的是孔明 張飛 關羽 劉備 ,孔明張飛年齡相同,再按Id倒序排序 } Console.ReadKey(); } //People類與上個同樣,省略
十二、ThenByDescending操做符
ThenByDescending操做符與ThenBy操做符很是相似,只是排序順序倒過來而已,不在過多闡述。
1三、Reverse操做符
Reverse操做符用於生成一個與輸入序列中元素相同,但元素排列順序相反的新序列。
方法原型:
public static IEnumerable<TSource> Reverse<TSource>(this IEnumerable<TSource> source);
從方法原型能夠看到,這個擴展方法,不須要輸入參數,返回一個新集合。
來看實例:
static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(2, "關羽", 22); People p3 = new People(3, "劉備", 23); People p4 = new People(4, "孔明", 21); pList.Add(p1); pList.Add(p2); pList.Add(p3); pList.Add(p4); IEnumerable<People> newList = pList.Reverse<People>(); //此處用的是List<T>,必需要寫類型參數,由於List<T>自己也有個同名方法 foreach (People p in newList) { Console.WriteLine(p.Name); //輸出 孔明 劉備 關羽 張飛 注意到順序是與原集合順序倒過來的。 } Console.ReadKey(); } //People類與上個同樣,省略
1四、Join操做符
Join操做符相似於SQL語句中的Join語句用於鏈接多個表,Linq to OBJECT中Join操做符能夠用來鏈接兩個輸入序列。
來看方法原型:
public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector); public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer);
能夠看到Join操做符的方法原型很是複雜,從方法原型能夠看到,參數outer和inner是須要鏈接的兩個輸入集合。其中outer表明的是調用的集合。當Join操做符被調用時,首先列舉inner序列中的全部元素,爲序列中每個類型爲U的元素調用委託InnerKeySelector,生成一個類型爲K的的對象innerKey做爲鏈接關鍵字。(至關於數據庫中的外鍵),將inner序列中的每個元素和其對應的鏈接關鍵字innerKey存儲在一個臨時哈希表中;其次列舉outer序列中的全部元素,爲每個類型爲T的元素調用委託outerKeySelector,生成一個類型爲K的對象outKey用做鏈接關鍵字,在第一步生成的臨時哈希表中查找與outKey相等的對應的innerKey對象,若是找到對應的記錄,會將當前outer序列中的類型爲T的元素和對應的inner序列中類型爲U的元素做爲一組參數傳遞給委託resultSelector,resultSelector會根據這兩個參數返回一個類型爲V的對象,此類型爲V的對象會被添加到Join操做符的輸出結果序列中去。Join操做符返回一個類型爲IEnumerable<T>的序列。
來看代碼示例:
class Program { static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(2, "關羽", 22); People p3 = new People(3, "劉備", 23); People p4 = new People(4, "孔明", 21); pList.Add(p1); pList.Add(p2); pList.Add(p3); pList.Add(p4); List<Record> rList = new List<Record>(); Record r1 = new Record(1, 3); Record r2 = new Record(2, 5); Record r3 = new Record(3, 7); Record r4 = new Record(4, 20); rList.Add(r1); rList.Add(r2); rList.Add(r3); rList.Add(r4); //下面一行代碼的意思是,將PList集合拼接rList集合,根據People的Id與Record的PId屬性(至關於外鍵)拼接,取People的姓名與Record的WarRecord返回 var Items = pList.Join(rList, p => p.Id, r => r.PId, (p, r) => new { Name = p.Name, WarRecord = r.WarRecord }); foreach (var item in Items) { Console.WriteLine(item.Name + ":" + item.WarRecord); //輸出 張飛:3 關羽:5 劉備:7,孔明:20 } Console.ReadKey(); } //People類與上個同樣,省略 } public class Record { public Record(int id, int warRecord) { this.PId = id; this.WarRecord = warRecord; } public int PId { get; set; } public int WarRecord { get; set; } } public class People { public People(int id, string name, int age) { this.Id = id; this.Name = name; this.Age = age; } public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } }
1五、GroupJoin操做符
GroupJoin操做符也用於鏈接兩個輸入序列,但與Join操做符不一樣稍有不一樣,Join操做符在列舉outer序列元素時,會將一個outer序列元素和其對應的inner序列元素做爲一組參數傳遞給委託resultSelector委託,這就意味着若是某一個outer序列元素有多個對應的inner序列元素,Join操做符將會分屢次將outer序列元素和每個對應的inner序列元素傳遞給委託resultSelector。使用GroupJoin操做符時,若是某一個outer序列元素有多個對應的inner序列元素,那麼這多個對應的inner序列元素會做用一個序列一次性傳遞給委託resultSelecotr,能夠針對此序列添加一些處理邏輯。
來看看GroupJoin操做符的方法原型:
public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector); public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey> comparer);
留意變紅的那個委託,注意,與Join操做符的不一樣點就是一個outer序列中若是有多個對應的inner序列元素,會做爲一個集合IEnumerable<TInner>傳遞到此委託。
來看代碼示例:
class Program { static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(2, "關羽", 22); People p3 = new People(3, "劉備", 23); People p4 = new People(4, "孔明", 21); pList.Add(p1); pList.Add(p2); pList.Add(p3); pList.Add(p4); List<Record> rList = new List<Record>(); Record r1 = new Record(1, 3); Record r2 = new Record(2, 5); Record r3 = new Record(3, 7); Record r4 = new Record(4, 20); Record r5 = new Record(1, 33); rList.Add(r1); rList.Add(r2); rList.Add(r3); rList.Add(r4); rList.Add(r5); //下面一行代碼的意思是,將PList集合拼接rList集合,根據People的Id與Record的PId屬性(至關於外鍵)拼接,取People的姓名與Record的WarRecord var Items = pList.Join(rList, p => p.Id, r => r.PId, (p, r) => new { Name = p.Name, WarRecord = r.WarRecord }); foreach (var item in Items) { Console.WriteLine(item.Name + ":" + item.WarRecord); //輸出 張飛:3 張飛:33 關羽:5 劉備:7,孔明:20 } Console.WriteLine(); var Items1 = pList.GroupJoin(rList, p => p.Id, r => r.PId, (p, List1) => new { Name = p.Name, WarRecords = List1.Sum(r=>r.WarRecord) }); foreach (var item in Items1) { Console.WriteLine(item.Name + ":" + item.WarRecords); //輸出 張飛:36 關羽:5 劉備:7,孔明:20 } //這個例子足以說明,Join與GrouyJoin的不一樣,Join每次都會傳遞一個元素到輸出序列,而GruopJoin會將相同序列序號做爲一個集合的形式傳遞給輸出委託 Console.ReadKey(); } //People類與上個同樣,省略 } public class Record { public Record(int id, int warRecord) { this.PId = id; this.WarRecord = warRecord; } public int PId { get; set; } public int WarRecord { get; set; } } public class People { public People(int id, string name, int age) { this.Id = id; this.Name = name; this.Age = age; } public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } }
1六、GroupBy操做符
GroupBy操做符相似於SQL語言仲的Gruop By語句,這裏的GroupBy操做符用於將輸入序列中的元素進行分組。
來看看GruopBy的方法原型:
static void Main(string[] args) { List<People> pList = new List<People>(); People p1 = new People(1, "張飛", 21); People p2 = new People(2, "關羽", 22); People p3 = new People(3, "劉備", 23); People p4 = new People(4, "孔明", 21); pList.Add(p1); pList.Add(p2); pList.Add(p3); pList.Add(p4); var pList1 = pList.GroupBy(p=>p.Age); foreach (var item in pList1) { Console.Write(item.Key); //輸出 21 22 23 能夠看出按照年齡分紅了三組 foreach (var item1 in item) { Console.Write(item1.Name); //輸出21 張飛 孔明 22關羽 24劉備 } Console.WriteLine(); } Console.ReadKey(); } //People類與上個同樣,省略
1七、Distinct操做符
Distinct操做符相似於SQL語句中的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);
代碼示例:
static void Main(string[] args) { List<int> listInt = new List<int>(); listInt.Add(1); listInt.Add(1); listInt.Add(2); listInt.Add(2); listInt.Add(2); IEnumerable<int> IEInt = listInt.Distinct(); foreach (var i in IEInt) { Console.WriteLine(i); //輸出 1 2 留意到重複的只出現一次 } Console.ReadKey(); }
1八、Union操做符
Union操做符用於將兩個序列中的元素合併成一個新的序列,新序列將自動去除重複的元素。
Union操做符與Concat操做符的區別在於,Union會自動去除重複元素,而Concat無論有沒有重複,全部都輸出。
來看方法原型:
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);
來看代碼示例:
static void Main(string[] args) { List<int> listInt = new List<int>(); listInt.Add(1); listInt.Add(2); listInt.Add(3); List<int> listInt1 = new List<int>(); listInt1.Add(2); listInt1.Add(3); listInt1.Add(4); IEnumerable<int> IEInt = listInt.Concat(listInt1); foreach (var i in IEInt) { Console.WriteLine(i); //輸出 1 2 3 2 3 4 } Console.WriteLine(); IEnumerable<int> IEInt1 = listInt.Union(listInt1); foreach (var i in IEInt1) { Console.WriteLine(i); //輸出 1 2 3 4 } //這個例子足以說明兩種鏈接的不一樣 Console.ReadKey(); }
1九、Intersect操做符
Intersect操做符會將兩個輸入序列中的重複元素,即同時存在於兩個序列中的元素挑選出來,生成一個新的集合,也就是求交集。
來看方法原型:
public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second);
代碼示例:
static void Main(string[] args) { List<int> listInt = new List<int>(); listInt.Add(1); listInt.Add(2); listInt.Add(3); List<int> listInt1 = new List<int>(); listInt1.Add(2); listInt1.Add(3); listInt1.Add(4); IEnumerable<int> IEInt = listInt.Intersect(listInt1); foreach (var i in IEInt) { Console.WriteLine(i); //輸出 2 3 //2 3是兩個集合的交集 } Console.ReadKey(); } //People類與上個同樣,省略
20、Except操做符
Except操做符能夠實現一種集合之間的減法運算,它返回兩個序列中存在於第一個序列但不存在於第二個序列的元素所組成的新序列。
來看方法原型:
public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second); public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer);
代碼示例:
static void Main(string[] args) { List<int> listInt = new List<int>(); listInt.Add(1); listInt.Add(2); listInt.Add(3); List<int> listInt1 = new List<int>(); listInt1.Add(2); listInt1.Add(3); listInt1.Add(4); IEnumerable<int> IEInt = listInt.Except(listInt1); foreach (var i in IEInt) { Console.WriteLine(i); //輸出 1` 只有1存在於第1個集合而不存在於第二個集合 } Console.ReadKey(); }
2一、Cast操做符
Cast操做符用於將一個類型爲IEnumerable的集合對象轉換爲IEnumerable<T>類型的集合對象。也就是非泛型集合轉成泛型集合,由於在Linq to OBJECT中,絕大部分操做符都是針對IEnumerable<T>類型進行的擴展方法。所以對非泛型集合並不適用。
來看方法原型,注意,此方法必須傳入類型參數。
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source);
來看代碼示例:
static void Main(string[] args) { ArrayList al = new ArrayList(); al.Add(1); al.Add(2); al.Add(3); IEnumerable<int> IEInt = al.Cast<int>(); //非泛型轉泛型 foreach (var i in IEInt) { Console.WriteLine(i); //輸出 1 2 3 } Console.ReadKey(); }
2二、OfType操做符
OfType操做符與Cast操做符相似,用於將類型爲IEnumerable的集合對象轉換爲IEnumerable<T>類型的集合對象。不一樣的是,Cast操做符會視圖將輸入序列中的全部元素轉換成類型爲T的對象,,若是有轉換失敗的元素存在Cast操做符將拋出一個異常;而OfType操做符僅會將可以成功轉換的元素進行轉換,並將這些結果添加到結果序列中去。與Cast操做符相比,OfType操做符更加安全。
來看下OfType操做符的方法原型:
public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source);
代碼示例:
static void Main(string[] args) { ArrayList al = new ArrayList(); al.Add(1); al.Add(2); al.Add("a"); //IEnumerable<int> IECast = al.Cast<int>(); //拋出異常 //foreach (var i in IECast) //{ // Console.WriteLine(i); //} IEnumerable<int> IEOfType = al.OfType<int>(); foreach (int i in IEOfType) { Console.WriteLine(i); //輸出 1 2 其中轉換不了的a不轉換 } Console.ReadKey(); }
2三、AsEnumeralbe操做符
AsEnumerable操做符能夠將一個類型爲IEnumerable<T>的輸入序列轉換成一個IEnumerable<T>的輸出序列,其主要用於將一個實現了IEnumerable<T>接口的對象轉換成一個標準的IEnumerable<T>接口對象。在Linq中、不一樣領域的Linq實現都有本身專屬的操做符。
例如IQueryable<T>一般是Linq to SQL的返回類型,當咱們直接在上面調用Where<>方法時,調用的是Linq to sql的擴展方法,所以有時候咱們須要轉換爲標準的IEnumerable<T>在能調用Linq to OBJECT的擴展方法。
來看方法原型:
public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source);
2四、DefaultEmpty操做符
DefaultEmpty操做符能夠用來爲一個空的輸入序列生成一個對應的含有默認元素的新序列。引用類型爲null,值類型爲相應的默認值。有些標準操做符在一個空的序列上調用時會拋出一個異常,而DefaultEmpty偏偏能夠解決這個問題。
方法原型:
public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source); public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source, TSource defaultValue);
代碼示例:
static void Main(string[] args) { List<string> ListInt = new List<string>(); ListInt.Add("one"); ListInt.Add("two"); ListInt.Add("three"); string str = ListInt.Where(s => s.StartsWith("a")).DefaultIfEmpty().First(); Console.WriteLine(str); //什麼也不輸出,或者說輸出空白 //string str1 = ListInt.Where(s => s.StartsWith("a")).First(); //若是去掉DefaultEmpty就會報異常("序列中不包含任何元素") Console.ReadKey(); }
2五、Range操做符
Range操做符用於輔助生成一個整數序列。
其方法原型以下:
public static IEnumerable<int> Range(int start, int count);
從方法原型能夠看出,這並非一個擴展方法,只是一個普通的靜態方法,其中第一個參數表示開始的數字,第二個是要生成的數量,返回一個IEnumerable<ine>的集合。
代碼示例以下:
static void Main(string[] args) { IEnumerable<int> ints = Enumerable.Range(1,10); foreach (int i in ints) { Console.WriteLine(i); //輸出 1 2 3 4 5 6 7 8 9 10 } Console.ReadKey(); }
2六、Repeat操做符
Repeat操做符用於生成一個包含指定數量重複元素的序列。
方法原型以下:
public static IEnumerable<TResult> Repeat<TResult>(TResult element, int count);
留意到這是一個泛型的靜態方法,你能夠生成任何類型重複的元素,第二個參數表明個數,第一個表示要重複生成的元素。
代碼示例:
static void Main(string[] args) { IEnumerable<int> ints = Enumerable.Repeat(1,10); foreach (int i in ints) { Console.WriteLine(i); //輸出 1 1 1 1 1 1 1 1 1 1 } Console.ReadKey(); }
2七、Empty操做符
Empty操做符用於生成一個包含指定類型元素的空序列。
方法原型以下:
public static IEnumerable<TResult> Empty<TResult>();
從方法原型能夠看出,這只是一個普通的靜態方法,可是挺有用,由於IEnumerable<T>是個接口,不能new,可是用這個方法能夠生成一個空的IEnumerable<T>對象了。
代碼示例:
static void Main(string[] args) { IEnumerable<int> ints = Enumerable.Empty<int>(); Console.WriteLine(ints.Count()); //輸出0 Console.ReadKey(); }