首頁 > 軟體

C#中Linq的入門教學

2022-05-26 22:01:28

一、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、立即執行的運運算元

對一系列源元素執行聚合函數的查詢必須首先回圈存取這些元素。CountMaxAverage 和 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用法的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com