C#中Linq的入門(mén)教程
一、LINQ的體系結(jié)構(gòu)
語(yǔ)言集成查詢 (LINQ) (C#) | Microsoft 官方文檔
LINQ總共包括五個(gè)部分:
| 程序集 | 命名空間 | 描述 |
---|---|---|---|
LINQ to Objects | System.Core.dll | System.Linq | 提供對(duì)內(nèi)存中集合操作的支持 |
LINQ to XML | System.Xml.Linq.dll | System.Xml.Linq | 提供對(duì)XML數(shù)據(jù)源的操作的支持 |
LINQ to SQL | System.Data.Linq.dll | System.Data.Linq | 提供對(duì)Sql Server數(shù)據(jù)源操作的支持。(微軟已宣布不再更新,推薦使用LINQ to Entities) |
LINQ to DataSet | System.Data.DataSetExtensions.dll | System.Data | 提供對(duì)離線數(shù)據(jù)集DataTable操作的支持。 |
LINQ to Entities | System.Core.dll 和System.Data.Entity.dll | System.Linq和System.Data.Objects | LINQ to Entities 是 Entity Framework 的一部分并且取代LINQ to SQL 作為在數(shù)據(jù)庫(kù)上使用 LINQ 的標(biāo)準(zhǔn)機(jī)制。 |
目前,除了以下的,還可以下載其他第三方提供程序,例如LINQ to JSON、LINQ to MySQL、LINQ to Amazon、LINQ to Flickr和LINQ to SharePoint。無(wú)論使用什么數(shù)據(jù)源,都可以通過(guò)LINQ使用相同的API進(jìn)行操作。
二、 LINQ的語(yǔ)法
1、Query查詢表達(dá)式語(yǔ)法
LINQ查詢表達(dá)式以from子句開(kāi)頭,以select子句或group子句結(jié)束。
在兩個(gè)子句之間,可以使用where、orderby、join、let等查詢操作符。
關(guān)鍵字有: from 、where 、select 、group 、into 、orderby、join、let、in、on、equals、by、ascending、descending等。
- from…in…:指定要查找的數(shù)據(jù)源以及范圍變量,多個(gè)from子句則表示從多個(gè)數(shù)據(jù)源查找數(shù)據(jù)。注意:c#編譯器會(huì)把“復(fù)合from子句”的查詢表達(dá)式轉(zhuǎn)換為SelectMany()擴(kuò)展方法。
- join…in…on…equals…:指定多個(gè)數(shù)據(jù)源的關(guān)聯(lián)方式
- let:引入用于存儲(chǔ)查詢表達(dá)式中子表達(dá)式結(jié)果的范圍變量。通常能達(dá)到層次感會(huì)更好,使代碼更易于閱讀。
- orderby、descending:指定元素的排序字段和排序方式。當(dāng)有多個(gè)排序字段時(shí),由字段順序確定主次關(guān)系,可指定升序和降序兩種排序方式
- where:指定元素的篩選條件。多個(gè)where子句則表示了并列條件,必須全部都滿足才能入選。每個(gè)where子句可以使用謂詞&&、||連接多個(gè)條件表達(dá)式。
- group:指定元素的分組字段。
- select:指定查詢要返回的目標(biāo)數(shù)據(jù),可以指定任何類型,甚至是匿名類型。(目前通常被指定為匿名類型)
- into:提供一個(gè)臨時(shí)的標(biāo)識(shí)符。該標(biāo)識(shí)可以引用join、group和select子句的結(jié)果。
1) 直接出現(xiàn)在join子句之后的into關(guān)鍵字會(huì)被翻譯為GroupJoin。(into之前的查詢變量可以繼續(xù)使用)
2) select或group子句之后的into它會(huì)重新開(kāi)始一個(gè)查詢,讓我們可以繼續(xù)引入where, orderby和select子句,它是對(duì)分步構(gòu)建查詢表達(dá)式的一種簡(jiǎn)寫(xiě)方式。(into之前的查詢變量都不可再使用)
編譯器會(huì)在程序編譯時(shí)轉(zhuǎn)換LINQ查詢,以調(diào)用相應(yīng)的擴(kuò)展方法。
下面是一個(gè)簡(jiǎn)單的示例,查詢一個(gè)int數(shù)組中小于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語(yǔ)句最終被轉(zhuǎn)換為調(diào)用IEnumerable<T>的擴(kuò)展方法,在System.Linq.Enumerable靜態(tài)類中定義了N多擴(kuò)展。所以只要繼承與IEnumerable的類都支持Linq查詢 。
2、Lambda語(yǔ)法
標(biāo)準(zhǔn)查詢操作符
Enumberable 類定義的標(biāo)準(zhǔn)查詢操作符。
- 篩選操作符:定義返回元素的條件。
Where:使用謂詞,返回符合條件的元素。
OfType<TResult>:返回符合類型的元素。 - 投射操作符:用于把對(duì)象轉(zhuǎn)換為另一個(gè)類型的新對(duì)象。
Select :定義根據(jù)選擇器函數(shù)選擇結(jié)果值的投射。
SelectMany:定義根據(jù)選擇器函數(shù)選擇結(jié)果值的投射。 - 排序操作符:改變返回的元素的順序。
Orderby: 升序排序。
OrderBydescending: 降序排序。
ThenBy 和 ThenByDescending: 二次排序。
Reverse: 反轉(zhuǎn)集合元素。 - 連接操作符:用于合并不直接相關(guān)的集合。
Join: 根據(jù)鍵選擇器函數(shù)連接兩個(gè)集合。
GroupJoin: 連接兩個(gè)集合,并分組。 - 組合操作符:把數(shù)據(jù)放在組中。
GroupBy : 組合公共鍵的元素。
ToLookup:創(chuàng)建一個(gè)一對(duì)多字典,組合元素。 - 限定(量詞)操作符:元素滿足指定的條件。
Any :部分滿足謂詞函數(shù)的元素。
All : 所有元素是否都滿足謂詞函數(shù)。
Contains: 檢查某個(gè)元素是否在集合中。 - 分區(qū)操作符:返回集合的子集。
Take: 從集合提取元素個(gè)數(shù)。
Skip :跳過(guò)指定的元素個(gè)數(shù),提取其他元素。
TakeWhile :提取條件為真的元素。
SkipWhile:提取條件為真的元素。 - Set操作符:返回一個(gè)集合。
Distinct :(去重)刪除重復(fù)的元素。
Union: (并集)返回集合中唯一元素。
Intersect:(交集)返回兩個(gè)集合都有的元素。
Except : (差集)只出現(xiàn)在一個(gè)集合中的元素。
Zip: 兩個(gè)集合合并為一個(gè)元素。 - 元素操作符:返回一個(gè)元素。
First:返回第一個(gè)滿足條件的元素。
FirstOrDefault:類似First,如果未找到,返回類型的默認(rèn)值。
Last:返回最后一個(gè)滿足條件的元素。
LastOrDefault:類似Last,如果未找到,返回類型的默認(rèn)值。
ElementAt:返回元素的位置。
ElementAtOrDefault:指定索引(超出索引,取默認(rèn)值)
Single:返回一個(gè)滿足條件的元素。如果有多個(gè)元素都滿足條件,就拋出一個(gè)異常。
SingleOrDefault:類似Single,如果非唯一或者找不到,返回類型的默認(rèn)值。 - 聚合操作符:計(jì)算集合值。
Sum: 總和。
Count: 所有元素個(gè)數(shù)。
LongCount:計(jì)數(shù)(大型集合)
Min: 最小元素。
Max : 最大元素。
Average: 平均值。
Aggregate: 根據(jù)輸入的表達(dá)式獲取聚合值。 - 轉(zhuǎn)換操作符:
ToArray:變成數(shù)組
AsEnumerable:變成IEnumeralbe<T>
AsQueryable:變成IQueryable
ToList:變成List<T>
ToDictionary:變成字典
Cast<TResult> :轉(zhuǎn)換
ToLookup:變一對(duì)多字典Lookup<Tkey,TElement> - 生成操作符:
Empty :空集合。
DefaultIfEmpty:默認(rèn)值集合
Range:返回一系列數(shù)字。
Repeat: 返回始終重復(fù)一直的集合。 - 等值操作
SequenceEqual:成對(duì)比較 - 串聯(lián)操作
Concat:串聯(lián)
3、擴(kuò)展方法存在對(duì)應(yīng)的查詢表達(dá)式關(guān)鍵字:
- Where:where
- Select:select
- SelectMany:使用多個(gè) 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、延遲執(zhí)行查詢
LINQ具有“延遲計(jì)算”的特性。
Linq的執(zhí)行不是在Linq的賦值語(yǔ)句執(zhí)行,而是在通過(guò)foreach遍歷訪問(wèn)結(jié)果時(shí)執(zhí)行。
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); }
返回的結(jié)果是:
兩次遍歷的結(jié)果不一樣,說(shuō)明執(zhí)行并不是在Linq的定義語(yǔ)句執(zhí)行,而是在foreach執(zhí)行。
換成如下,兩次執(zhí)行結(jié)果就一樣了。
var namesWithJ = (from n in names where n.StartsWith("J") orderby n select n ).ToList();
2、運(yùn)算符延遲計(jì)算符號(hào)
按字母順序整理:
1、具有延遲計(jì)算的運(yùn)算符
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、立即執(zhí)行的運(yùn)算符
對(duì)一系列源元素執(zhí)行聚合函數(shù)的查詢必須首先循環(huán)訪問(wèn)這些元素。Count、Max、Average 和 First 就屬于此類查詢。
由于查詢本身必須使用 foreach 以便返回結(jié)果,因此這些查詢?cè)趫?zhí)行時(shí)不使用顯式 foreach 語(yǔ)句,直接立即執(zhí)行。
Aggregate,All,Any,Average,Contains,Count,ElementAt,ElementAtOrDefault,Empty,F(xiàn)irst,F(xiàn)irstOrDefault,Last,LastOrDefault,LongCount,Max,Min,Range,SequenceEqual,Single,SingleOrDefault,Sum,ToArray,ToDictionary,ToList,ToLookup
注意:特殊的AsEnumerable運(yùn)算符,用于處理LINQ to Entities操作遠(yuǎn)程數(shù)據(jù)源,將IQueryable遠(yuǎn)程數(shù)據(jù)立即轉(zhuǎn)化為本地的IEnumerable集合。若AsEnumerable接收參數(shù)是IEnumerable內(nèi)存集合則什么都不做。
3、強(qiáng)制立即執(zhí)行
若要強(qiáng)制立即執(zhí)行任意查詢并緩存其結(jié)果,可以調(diào)用 ToList<TSource> 或 ToArray<TSource> 方法。
通過(guò)調(diào)用 ToList 或 ToArray,可以將所有數(shù)據(jù)緩存在單個(gè)集合對(duì)象中。
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 進(jìn)行數(shù)據(jù)轉(zhuǎn)換
語(yǔ)言集成查詢 (LINQ) 不僅可用于檢索數(shù)據(jù),而且還是一個(gè)功能強(qiáng)大的數(shù)據(jù)轉(zhuǎn)換工具。
通過(guò)使用 LINQ 查詢,您可以將源序列用作輸入,并采用多種方式修改它以創(chuàng)建新的輸出序列。您可以通過(guò)排序和分組來(lái)修改該序列,而不必修改元素本身。
但是,LINQ 查詢的最強(qiáng)大的功能是能夠創(chuàng)建新類型。這一功能在 select 子句中實(shí)現(xiàn)。
例如,可以執(zhí)行下列任務(wù):
1、將多個(gè)輸入聯(lián)接到一個(gè)輸出序列
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) { //創(chuàng)建第一個(gè)數(shù)據(jù)源 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 = "夢(mèng)里", Name = "小叁", Scores = new List<int> () { 86, 68, 73, 97 } } }; //創(chuàng)建第二個(gè)數(shù)據(jù)源 var teachers = new List<Teacher>() { new Teacher () { Age = 35, City = "夢(mèng)里", Name = "啵哆" }, new Teacher () { Age = 28, City = "云南", Name = "小紅" }, new Teacher () { Age = 38, City = "河南", Name = "麗麗" } }; //創(chuàng)建查詢 var peopleInDreams = (from student in students where student.City == "夢(mèng)里" select student.Name) .Concat(from teacher in teachers where teacher.City == "夢(mèng)里" select teacher.Name); //執(zhí)行查詢 foreach (var person in peopleInDreams) { Console.WriteLine(person); } Console.Read(); }
結(jié)果
小叁
啵哆
2、選擇各個(gè)源元素的子集
1. 若要只選擇源元素的一個(gè)成員,請(qǐng)使用點(diǎn)運(yùn)算。
var query = from cust in Customers select cust.City;
2. 若要?jiǎng)?chuàng)建包含源元素的多個(gè)屬性的元素,可以使用具有命名對(duì)象或匿名類型的對(duì)象初始值設(shè)定項(xiàng)。
var query = from cust in Customer select new {Name = cust.Name, City = cust.City};
3、將內(nèi)存中的對(duì)象轉(zhuǎn)換為 XML
//創(chuàng)建數(shù)據(jù)源 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 } } }; //創(chuàng)建查詢 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)) ); //執(zhí)行查詢 Console.WriteLine(studentsToXml);
4、 對(duì)源元素執(zhí)行操作
輸出序列可能不包含源序列的任何元素或元素屬性。
輸出可能是通過(guò)將源元素用作輸入?yún)?shù)計(jì)算出的值的序列。
//數(shù)據(jù)源 double[] radii = { 1, 2, 3 }; //創(chuàng)建查詢 var query = from radius in radii select $"{radius * radius * 3.14}"; //執(zhí)行查詢 foreach (var i in query) { Console.WriteLine(i); }
到此這篇關(guān)于C#中Linq用法的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#byte數(shù)組與Image的相互轉(zhuǎn)換實(shí)例代碼
這篇文章主要介紹了C#byte數(shù)組與Image的相互轉(zhuǎn)換實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-04-04WCF如何使用動(dòng)態(tài)代理精簡(jiǎn)代碼架構(gòu)
這篇文章主要介紹了WCF如何使用動(dòng)態(tài)代理精簡(jiǎn)代碼架構(gòu),幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-03-03C#使用SQL Dataset數(shù)據(jù)集代碼實(shí)例
今天小編就為大家分享一篇關(guān)于的文章,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10