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