C#中Linq的入門教程
一、LINQ的體系結構
語言集成查詢 (LINQ) (C#) | Microsoft 官方文檔
LINQ總共包括五個部分:
|
程序集 |
命名空間 |
描述 |
---|---|---|---|
LINQ to Objects |
System.Core.dll |
System.Linq |
提供對內存中集合操作的支持 |
LINQ to XML |
System.Xml.Linq.dll |
System.Xml.Linq |
提供對XML數據源的操作的支持 |
LINQ to SQL |
System.Data.Linq.dll |
System.Data.Linq |
提供對Sql Server數據源操作的支持。(微軟已宣佈不再更新,推薦使用LINQ to Entities) |
LINQ to DataSet |
System.Data.DataSetExtensions.dll |
System.Data |
提供對離線數據集DataTable操作的支持。 |
LINQ to Entities |
System.Core.dll 和System.Data.Entity.dll |
System.Linq和System.Data.Objects |
LINQ to Entities 是 Entity Framework 的一部分並且取代LINQ to SQL 作為在數據庫上使用 LINQ 的標準機制。 |
目前,除瞭以下的,還可以下載其他第三方提供程序,例如LINQ to JSON、LINQ to MySQL、LINQ to Amazon、LINQ to Flickr和LINQ to SharePoint。無論使用什麼數據源,都可以通過LINQ使用相同的API進行操作。
二、 LINQ的語法
1、Query查詢表達式語法
LINQ查詢表達式以from子句開頭,以select子句或group子句結束。
在兩個子句之間,可以使用where、orderby、join、let等查詢操作符。
關鍵字有: from 、where 、select 、group 、into 、orderby、join、let、in、on、equals、by、ascending、descending等。
- from…in…:指定要查找的數據源以及范圍變量,多個from子句則表示從多個數據源查找數據。註意:c#編譯器會把“復合from子句”的查詢表達式轉換為SelectMany()擴展方法。
- join…in…on…equals…:指定多個數據源的關聯方式
- let:引入用於存儲查詢表達式中子表達式結果的范圍變量。通常能達到層次感會更好,使代碼更易於閱讀。
- orderby、descending:指定元素的排序字段和排序方式。當有多個排序字段時,由字段順序確定主次關系,可指定升序和降序兩種排序方式
- where:指定元素的篩選條件。多個where子句則表示瞭並列條件,必須全部都滿足才能入選。每個where子句可以使用謂詞&&、||連接多個條件表達式。
- group:指定元素的分組字段。
- select:指定查詢要返回的目標數據,可以指定任何類型,甚至是匿名類型。(目前通常被指定為匿名類型)
- into:提供一個臨時的標識符。該標識可以引用join、group和select子句的結果。
1) 直接出現在join子句之後的into關鍵字會被翻譯為GroupJoin。(into之前的查詢變量可以繼續使用)
2) select或group子句之後的into它會重新開始一個查詢,讓我們可以繼續引入where, orderby和select子句,它是對分步構建查詢表達式的一種簡寫方式。(into之前的查詢變量都不可再使用)
編譯器會在程序編譯時轉換LINQ查詢,以調用相應的擴展方法。
下面是一個簡單的示例,查詢一個int數組中小於5的元素,並按照從小到大的順序排列:
int[] arr = new int[] { 1, 4, 2, 6, 7, 9, 5, 1, 2, 4 }; var query = from r in arr where r < 5 orderby r select r; foreach (var item in query) { Console.WriteLine(item); } Console.ReadLine();
Linq語句最終被轉換為調用IEnumerable<T>的擴展方法,在System.Linq.Enumerable靜態類中定義瞭N多擴展。所以隻要繼承與IEnumerable的類都支持Linq查詢 。
2、Lambda語法
標準查詢操作符
Enumberable 類定義的標準查詢操作符。
- 篩選操作符:定義返回元素的條件。
Where:使用謂詞,返回符合條件的元素。
OfType<TResult>:返回符合類型的元素。 - 投射操作符:用於把對象轉換為另一個類型的新對象。
Select :定義根據選擇器函數選擇結果值的投射。
SelectMany:定義根據選擇器函數選擇結果值的投射。 - 排序操作符:改變返回的元素的順序。
Orderby: 升序排序。
OrderBydescending: 降序排序。
ThenBy 和 ThenByDescending: 二次排序。
Reverse: 反轉集合元素。 - 連接操作符:用於合並不直接相關的集合。
Join: 根據鍵選擇器函數連接兩個集合。
GroupJoin: 連接兩個集合,並分組。 - 組合操作符:把數據放在組中。
GroupBy : 組合公共鍵的元素。
ToLookup:創建一個一對多字典,組合元素。 - 限定(量詞)操作符:元素滿足指定的條件。
Any :部分滿足謂詞函數的元素。
All : 所有元素是否都滿足謂詞函數。
Contains: 檢查某個元素是否在集合中。 - 分區操作符:返回集合的子集。
Take: 從集合提取元素個數。
Skip :跳過指定的元素個數,提取其他元素。
TakeWhile :提取條件為真的元素。
SkipWhile:提取條件為真的元素。 - Set操作符:返回一個集合。
Distinct :(去重)刪除重復的元素。
Union: (並集)返回集合中唯一元素。
Intersect:(交集)返回兩個集合都有的元素。
Except : (差集)隻出現在一個集合中的元素。
Zip: 兩個集合合並為一個元素。 - 元素操作符:返回一個元素。
First:返回第一個滿足條件的元素。
FirstOrDefault:類似First,如果未找到,返回類型的默認值。
Last:返回最後一個滿足條件的元素。
LastOrDefault:類似Last,如果未找到,返回類型的默認值。
ElementAt:返回元素的位置。
ElementAtOrDefault:指定索引(超出索引,取默認值)
Single:返回一個滿足條件的元素。如果有多個元素都滿足條件,就拋出一個異常。
SingleOrDefault:類似Single,如果非唯一或者找不到,返回類型的默認值。 - 聚合操作符:計算集合值。
Sum: 總和。
Count: 所有元素個數。
LongCount:計數(大型集合)
Min: 最小元素。
Max : 最大元素。
Average: 平均值。
Aggregate: 根據輸入的表達式獲取聚合值。 - 轉換操作符:
ToArray:變成數組
AsEnumerable:變成IEnumeralbe<T>
AsQueryable:變成IQueryable
ToList:變成List<T>
ToDictionary:變成字典
Cast<TResult> :轉換
ToLookup:變一對多字典Lookup<Tkey,TElement> - 生成操作符:
Empty :空集合。
DefaultIfEmpty:默認值集合
Range:返回一系列數字。
Repeat: 返回始終重復一直的集合。 - 等值操作
SequenceEqual:成對比較 - 串聯操作
Concat:串聯
3、擴展方法存在對應的查詢表達式關鍵字:
- Where:where
- Select:select
- SelectMany:使用多個 from 子句
- OrderBy:orderby
- ThenBy:orderby …, …
- OrderByDescending:orderby … descending
- ThenByDescending:orderby …, … descending
- GroupBy:group … by 或 group … by … into …
- Join:join … in … on … equals …
- GroupJoin: join … in … on … equals … into …
三、LINQ的特性
1、延遲執行查詢
LINQ具有“延遲計算”的特性。
Linq的執行不是在Linq的賦值語句執行,而是在通過foreach遍歷訪問結果時執行。
var names = new List<string> { "Nino", "Alberto", "Juan", "Mike", "Phil" }; var namesWithJ = (from n in names where n.StartsWith("J") orderby n select n); Console.WriteLine("First iteration"); foreach (string name in namesWithJ) { Console.WriteLine(name); } Console.WriteLine(); names.Add("John"); names.Add("Jim"); names.Add("Jack"); names.Add("Denny"); Console.WriteLine("Second iteration"); foreach (string name in namesWithJ) { Console.WriteLine(name); }
返回的結果是:
兩次遍歷的結果不一樣,說明執行並不是在Linq的定義語句執行,而是在foreach執行。
換成如下,兩次執行結果就一樣瞭。
var namesWithJ = (from n in names where n.StartsWith("J") orderby n select n ).ToList();
2、運算符延遲計算符號
按字母順序整理:
1、具有延遲計算的運算符
Cast,Concat,DefaultIfEmpty,Distinct,Except,GroupBy,GroupJoin,Intersect,Join,OfType,OrderBy,OrderByDescending,Repeat,Reverse,Select,SelectMany,Skip,SkipWhile,Take,TakeWhile,ThenBy,ThenByDescending,Union,Where,Zip
2、立即執行的運算符
對一系列源元素執行聚合函數的查詢必須首先循環訪問這些元素。Count、Max、Average 和 First 就屬於此類查詢。
由於查詢本身必須使用 foreach 以便返回結果,因此這些查詢在執行時不使用顯式 foreach 語句,直接立即執行。
Aggregate,All,Any,Average,Contains,Count,ElementAt,ElementAtOrDefault,Empty,First,FirstOrDefault,Last,LastOrDefault,LongCount,Max,Min,Range,SequenceEqual,Single,SingleOrDefault,Sum,ToArray,ToDictionary,ToList,ToLookup
註意:特殊的AsEnumerable運算符,用於處理LINQ to Entities操作遠程數據源,將IQueryable遠程數據立即轉化為本地的IEnumerable集合。若AsEnumerable接收參數是IEnumerable內存集合則什麼都不做。
3、強制立即執行
若要強制立即執行任意查詢並緩存其結果,可以調用 ToList<TSource> 或 ToArray<TSource> 方法。
通過調用 ToList 或 ToArray,可以將所有數據緩存在單個集合對象中。
var numQuery2 = (from num in numbers where (num % 2) == 0 select num).ToList(); var numQuery3 = (from num in numbers where (num % 2) == 0 select num).ToArray();
四、使用 LINQ 進行數據轉換
語言集成查詢 (LINQ) 不僅可用於檢索數據,而且還是一個功能強大的數據轉換工具。
通過使用 LINQ 查詢,您可以將源序列用作輸入,並采用多種方式修改它以創建新的輸出序列。您可以通過排序和分組來修改該序列,而不必修改元素本身。
但是,LINQ 查詢的最強大的功能是能夠創建新類型。這一功能在 select 子句中實現。
例如,可以執行下列任務:
1、將多個輸入聯接到一個輸出序列
class Student { public string Name { get; set; } public int Age { get; set; } public string City { get; set; } public List<int> Scores { get; set; } } class Teacher { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string City { get; set; } } private static void Main(string[] args) { //創建第一個數據源 var students = new List<Student>() { new Student () { Age = 23, City = "廣州", Name = "小C", Scores = new List<int> () { 85, 88, 83, 97 } }, new Student () { Age = 18, City = "廣西", Name = "小明", Scores = new List<int> () { 86, 78, 85, 90 } }, new Student () { Age = 33, City = "夢裡", Name = "小叁", Scores = new List<int> () { 86, 68, 73, 97 } } }; //創建第二個數據源 var teachers = new List<Teacher>() { new Teacher () { Age = 35, City = "夢裡", Name = "啵哆" }, new Teacher () { Age = 28, City = "雲南", Name = "小紅" }, new Teacher () { Age = 38, City = "河南", Name = "麗麗" } }; //創建查詢 var peopleInDreams = (from student in students where student.City == "夢裡" select student.Name) .Concat(from teacher in teachers where teacher.City == "夢裡" select teacher.Name); //執行查詢 foreach (var person in peopleInDreams) { Console.WriteLine(person); } Console.Read(); }
結果
小叁
啵哆
2、選擇各個源元素的子集
1. 若要隻選擇源元素的一個成員,請使用點運算。
var query = from cust in Customers select cust.City;
2. 若要創建包含源元素的多個屬性的元素,可以使用具有命名對象或匿名類型的對象初始值設定項。
var query = from cust in Customer select new {Name = cust.Name, City = cust.City};
3、將內存中的對象轉換為 XML
//創建數據源 var students = new List<Student>() { new Student() { Age = 18, Name = "小A", Scores = new List<int>() {88,85,74,66 } }, new Student() { Age = 35, Name = "小B", Scores = new List<int>() {88,85,74,66 } }, new Student() { Age = 28, Name = "小啥", Scores = new List<int>() {88,85,74,66 } } }; //創建查詢 var studentsToXml = new XElement("Root", from student in students let x = $"{student.Scores[0]},{student.Scores[1]},{student.Scores[2]},{student.Scores[3]}" select new XElement("student", new XElement("Name", student.Name), new XElement("Age", student.Age), new XElement("Scores", x)) ); //執行查詢 Console.WriteLine(studentsToXml);
4、 對源元素執行操作
輸出序列可能不包含源序列的任何元素或元素屬性。
輸出可能是通過將源元素用作輸入參數計算出的值的序列。
//數據源 double[] radii = { 1, 2, 3 }; //創建查詢 var query = from radius in radii select $"{radius * radius * 3.14}"; //執行查詢 foreach (var i in query) { Console.WriteLine(i); }
到此這篇關於C#中Linq用法的文章就介紹到這瞭。希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。