[C#] 開始使用 LINQ

来源:http://www.cnblogs.com/liqingwen/archive/2016/09/02/5832322.html
-Advertisement-
Play Games

開始使用 LINQ 在此之前曾發表過三篇關於 LINQ 的隨筆: 進階:《LINQ 標準查詢操作概述》(強烈推薦) 技巧:《Linq To Objects - 如何操作字元串》 和 《Linq To Objects - 如何操作文件目錄》 現在,自己打算再整理一篇關於 LINQ 入門的隨筆。 序 語 ...


開始使用 LINQ 

  在此之前曾發表過三篇關於 LINQ 的隨筆:

    進階:《LINQ 標準查詢操作概述(強烈推薦)

    技巧:《Linq To Objects - 如何操作字元串》 和 《Linq To Objects - 如何操作文件目錄

  現在,自己打算再整理一篇關於 LINQ 入門的隨筆。為了避免篇幅過長,最終還是選擇將代碼摺疊起來。

  語言集成查詢 (LINQ) 是 Visual Studio 2008 和 .NET Framework 3.5 版中引入的一項創新功能。

  傳統上,針對數據的查詢都是以簡單的字元串表示,而沒有編譯時類型檢查或 IntelliSense 支持。此外,您還必須針對以下各種數據源學習一種不同的查詢語言:SQL 資料庫、XML 文檔、各種 Web 服務等等。 通過LINQ, 您可以使用語言關鍵字和熟悉的運算符針對強類型化對象集合編寫查詢。

  

  在 Visual Studio 中,可以為以下數據源編寫 LINQ 查詢:SQL Server 資料庫、XML 文檔、ADO.NET 數據集,以及支持 IEnumerable 或泛型 IEnumerable<T> 介面的任意對象集合。   使用要求:項目 ≥ .NET Framework 3.5 。  

目錄

 

一、介紹 LINQ 查詢

  查詢是一種從數據源檢索數據的表達式。隨著時間的推移,人們已經為各種數據源開發了不同的語言;例如,用於關係資料庫的 SQL 和用於 XML 的 XQuery。因此,開發人員不得不針對他們必須支持的每種數據源或數據格式而學習新的查詢語言。LINQ 通過提供一種跨數據源和數據格式使用數據的一致模型,簡化了這一情況。在 LINQ 查詢中,始終會用到對象。可以使用相同的編碼模式來查詢和轉換 XML 文檔、SQL 資料庫、ADO.NET 數據集、.NET 集合中的數據以及對其有 LINQ 提供程式可用的任何其他格式的數據。  

  1.1 查詢操作的三個部分

  操作三部曲:①取數據源 ②創建查詢 ③執行查詢

 1 internal class Program
 2 {
 3         private static void Main(string[] args)
 4         {
 5             //1.獲取數據源
 6             var nums = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
 7 
 8             //2.創建查詢
 9             var numQuery =
10                 from num in nums
11                 where (num % 2) == 0
12                 select num;
13 
14             //3.執行查詢
15             foreach (var num in numQuery)
16             {
17                 Console.WriteLine("{0}", num);
18             }
19         }
20 }
View Code

 

   下圖顯示了完整的查詢操作。在 LINQ 中,查詢的執行與查詢本身截然不同;換句話說,查詢本身指的是只創建查詢變數,不檢索任何數據。

  

  1.2 數據源

  在上一個示例中,由於數據源是數組,因此它隱式支持泛型 IEnumerable<T> 介面。支持 IEnumerable<T> 或派生介面(如泛型 IQueryable<T>)的類型稱為可查詢類型。  

  可查詢類型不需要進行修改或特殊處理就可以用作 LINQ 數據源。如果源數據還沒有作為可查詢類型出現在記憶體中,則 LINQ 提供程式必須以此方式表示源數據。例如,LINQ to XML 將 XML 文檔載入到可查詢的 XElement 類型中:
  //從 XML 中創建數據源
  //using System.Xml.Linq;
  var contacts = XElement.Load(@"c:\xxx.xml");

  

  在 LINQ to SQL 中,首先需要創建對象關係映射。 針對這些對象編寫查詢,然後由 LINQ to SQL 在運行時處理與資料庫的通信。

1     var  db = new Northwnd(@"c:\northwnd.mdf");
2     
3     //查詢在倫敦的客戶
4     var custQuery =
5         from cust in db.Customers
6         where cust.City == "London"
7         select cust;
Customers 表示資料庫中的特定表

 

  1.3 查詢

  查詢指定要從數據源中檢索的信息。 查詢還可以指定在返回這些信息之前如何對其進行排序、分組和結構化。 查詢存儲在查詢變數中,並用查詢表達式進行初始化。

  之前的示例中的查詢是從整數數組中返回所有的偶數。 該查詢表達式包含三個子句:fromwhere 和 select。(如果您熟悉 SQL,您會註意到這些子句的順序與 SQL 中的順序相反。)from 子句指定數據源,where 子句指定應用篩選器,select 子句指定返回的元素的類型。 目前需要註意的是,在 LINQ 中,查詢變數本身不執行任何操作並且不返回任何數據。 它只是存儲在以後某個時刻執行查詢時為生成結果而必需的信息。  

  1.4 查詢執行

  1.延遲執行

    如前所述,查詢變數本身只是存儲查詢命令。  實際的查詢執行會延遲到在 foreach 語句中迴圈訪問查詢變數時發生。 此概念稱為“延遲執行”。

  2.強制立即執行

    對一系列源元素執行聚合函數的查詢必須首先迴圈訪問這些元素。CountMaxAverage 和 First 就屬於此類查詢。由於查詢本身必須使用 foreach 以便返回結果,因此這些查詢在執行時不使用顯式 foreach 語句。另外還要註意,這些類型的查詢返回單個值,而不是 IEnumerable 集合。 

1     var numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
2 
3     var evenNumQuery =
4         from num in numbers
5         where (num % 2) == 0
6         select num;
7 
8     var evenNumCount = evenNumQuery.Count();
View Code

 

  若要強制立即執行任意查詢並緩存其結果,可以調用 ToList<TSource> 或 ToArray<TSource> 方法。

1     var numQuery2 =
2            (from num in numbers
3             where (num % 2) == 0
4             select num).ToList();
5 
6     var numQuery3 =
7           (from num in numbers
8            where (num % 2) == 0
9             select num).ToArray();
View Code

 

  此外,還可以通過在緊跟查詢表達式之後的位置放置一個 foreach 迴圈來強制執行查詢。但是,通過調用 ToList 或 ToArray,也可以將所有數據緩存在單個集合對象中。 

 

二、基本 LINQ 查詢操作

  2.1 獲取數據源:from

  在 LINQ 查詢中,第一步是指定數據源。像在大多數編程語言中一樣,必須先聲明變數,才能使用它。在 LINQ 查詢中,最先使用 from 子句的目的是引入數據源和範圍變數。

1     //queryAllCustomers 是 IEnumerable<Cutsomer> 類型
2     //數據源 (customers) 和範圍變數 (cust)
3     var queryAllCustomers = from cust in customers
4                                            select cust;
View Code

  範圍變數類似於 foreach 迴圈中的迭代變數,但在查詢表達式中,實際上不發生迭代。執行查詢時,範圍變數將用作對 customers 中的每個後續元素的引用。因為編譯器可以推斷 cust 的類型,所以您不必顯式指定此類型。

 

  2.2 篩選:where

  也許最常用的查詢操作是應用布爾表達式形式的篩選器。此篩選器使查詢只返回那些表達式結果為 true 的元素。使用 where 子句生成結果。實際上,篩選器指定從源序列中排除哪些元素。

1     var queryLondonCustomers = from cust in customers
2                                   where cust.City = "London"
3                                     select cust;
只返回地址位於倫敦的 customers。

  您可以使用熟悉的 C# 邏輯 AND(&&)和 OR(||) 運算符來根據需要在 where 子句中應用任意數量的篩選表達式。 

where cust.City = "London" && cust.Name = "Devon"
若要只返回位於“倫敦”和姓名為“Devon”的客戶
where cust.City = "London" || cust.Name = "Paris"
若要返回位於倫敦或巴黎的客戶

 

  2.3 排序:orderby

  通常可以很方便地將返回的數據進行排序。orderby 子句將使返回的序列中的元素按照被排序的類型的預設比較器進行排序。

1     var queryLondonCustomers = from cust in customers
2                                where cust.City = "London"
3                                orderby cust.Name descending 
4                                select cust;
按 Name 屬性對結果進行排序

  因為 Name 是一個字元串,所以預設比較器執行從 A 到 Z 的字母排序。若要按相反順序(從 Z 到 A)對結果進行排序,請使用 orderby…descending 子句。

 

  2.4 分組:group

  使用 group 子句,您可以按指定的鍵分組結果。

 1     var queryLondonCustomers = from cust in customers
 2                     group cust by cust.City;
 3 
 4     foreach (var queryLondonCustomer in queryLondonCustomers)
 5     {
 6        Console.WriteLine(queryLondonCustomer.Key);
 7        foreach (var cust in queryLondonCustomer)
 8        {
 9           Console.WriteLine(cust.Name);
10        }
11     }
您可以指定結果應按 City 分組,以便位於倫敦或巴黎的所有客戶位於各自組中。

  在本例中,cust.City 是鍵。

  在使用 group 子句結束查詢時,結果採用列表的列表形式。列表中的每個元素是一個具有 Key 成員及根據該鍵分組的元素列表的對象。在迴圈訪問生成組序列的查詢時,您必須使用嵌套的 foreach 迴圈。外部迴圈用於迴圈訪問每個組,內部迴圈用於迴圈訪問每個組的成員。  

  如果您必須引用組操作的結果,可以使用 into 關鍵字來創建可進一步查詢的標識符。

1     //custQuery 是 IEnumable<IGrouping<string, Customer>> 類型
2     var custQuery = from cust in customers
3                     group cust by cust.City
4                     into custGroup
5                     where custGroup.Count() > 2
6                     orderby custGroup.Key
7                     select custGroup;
這裡的查詢只返回那些包含兩個以上的客戶的組。

 

  2.5 聯接:join

  聯接運算創建數據源中沒有顯式建模的序列之間的關聯。例如,您可以執行聯接來查找位於同一地點的所有客戶和經銷商。在 LINQ 中,join 子句始終針對對象集合而非直接針對資料庫表運行。  

1     var innerJoinQuery = from cust in customers
2                        join dist in distributors on cust.City equals dist.City
3                        select new {CustomerName = cust.Name, DistributorName = dist.Name};
例如,您可以執行聯接來查找位於同一地點的所有客戶和經銷商。

  在 LINQ 中,join 子句始終針對對象集合而非直接針對資料庫表運行。  

  在 LINQ 中,您不必像在 SQL 中那樣頻繁使用 join,因為 LINQ 中的外鍵在對象模型中表示為包含項集合的屬性。

    from order in Customer.Orders...
例如,Customer 對象包含 Order 對象的集合。不必執行聯接,只需使用點表示法訪問訂單。

  

  2.6 選擇(投影):select

  select 子句生成查詢結果並指定每個返回的元素的“形狀”或類型。

  例如,您可以指定結果包含的是整個 Customer 對象、僅一個成員、成員的子集,還是某個基於計算或新對象創建的完全不同的結果類型。當 select 子句生成除源元素副本以外的內容時,該操作稱為“投影”。

 

三、使用 LINQ 進行數據轉換

  語言集成查詢 (LINQ) 不僅可用於檢索數據,而且還是一個功能強大的數據轉換工具。通過使用 LINQ 查詢,您可以將源序列用作輸入,並採用多種方式修改它以創建新的輸出序列。您可以通過排序和分組來修改該序列,而不必修改元素本身。但是,LINQ 查詢的最強大的功能是能夠創建新類型。這一功能在 select 子句中實現。 例如,可以執行下列任務:  

  

  3.1 將多個輸入聯接到一個輸出序列

 1     class Student
 2     {
 3         public string Name { get; set; }
 4 
 5         public int Age { get; set; }
 6 
 7         public string City { get; set; }
 8 
 9         public List<int> Scores { get; set; }
10     }
11 
12     class Teacher
13     {
14         public int Id { get; set; }
15 
16         public string Name { get; set; }
17 
18         public int Age { get; set; }
19 
20         public string City { get; set; }
21 
22     }
學生和老師兩個類
 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             //創建第一個數據源
 6             var students = new List<Student>()
 7             {
 8                 new Student()
 9                 {
10                     Age = 23,
11                     City = "廣州",
12                     Name = "小C",
13                     Scores = new List<int>(){85,88,83,97}
14                 },
15                 new Student()
16                 {
17                     Age = 18,
18                     City = "廣西",
19                     Name = "小明",
20                     Scores = new List<int>(){86,78,85,90}
21                 },
22                 new Student()
23                 {
24                     Age = 33,
25                     City = "夢裡",
26                     Name = "小叄",
27                     Scores = new List<int>(){86,68,73,97}
28                 }
29             };
30 
31             //創建第二個數據源
32             var teachers = new List<Teacher>()
33             {
34                 new Teacher()
35                 {
36                     Age = 35,
37                     City = "夢裡",
38                     Name = "啵哆"
39                 },
40                 new Teacher()
41                 {
42                     Age = 28,
43                     City = "雲南",
44                     Name = "小紅"
45                 },
46                 new Teacher()
47                 {
48                     Age = 38,
49                     City = "河南",
50                     Name = "麗麗"
51                 }
52             };
53 
54             //創建查詢
55             var peopleInDreams = (from student in students
56                             where student.City == "夢裡"
57                             select student.Name)
58                             .Concat(from teacher in teachers
59                                     where teacher.City == "夢裡"
60                                     select teacher.Name);
61 
62             //執行查詢
63             foreach (var person in peopleInDreams)
64             {
65                 Console.WriteLine(person);
66             }
67 
68             Console.Read();
69         }
70     }
控制台輸出代碼。

 

  3.2 選擇各個源元素的子集

  1. 若要只選擇源元素的一個成員,請使用點運算。

1     var query = from cust in Customers
2                     select cust.City;

  

  2. 若要創建包含源元素的多個屬性的元素,可以使用具有命名對象或匿名類型的對象初始值設定項。

1     var query = from cust in Customer
2                    select new {Name = cust.Name, City = cust.City};

 

  3.3 將記憶體中的對象轉換為 XML

 1             //創建數據源
 2             var students = new List<Student>()
 3             {
 4                 new Student()
 5                 {
 6                     Age = 18,
 7                     Name = "小A",
 8                     Scores = new List<int>() {88,85,74,66 }
 9                 },
10                 new Student()
11                 {
12                     Age = 35,
13                     Name = "小B",
14                     Scores = new List<int>() {88,85,74,66 }
15                 },
16                 new Student()
17                 {
18                     Age = 28,
19                     Name = "小啥",
20                     Scores = new List<int>() {88,85,74,66 }
21                 }
22             };
23 
24             //創建查詢
25             var studentsToXml = new XElement("Root",
26                 from student in students
27                 let x = $"{student.Scores[0]},{student.Scores[1]},{student.Scores[2]},{student.Scores[3]}"
28                 select new XElement("student",
29                 new XElement("Name", student.Name),
30                 new XElement("Age", student.Age),
31                 new XElement("Scores", x))
32             );
33 
34             //執行查詢
35             Console.WriteLine(studentsToXml);
View Code

 

  3.4 對源元素執行操作

  輸出序列可能不包含源序列的任何元素或元素屬性。輸出可能是通過將源元素用作輸入參數計算出的值的序列。

 1             //數據源
 2             double[] radii = {1, 2, 3};
 3 
 4             //創建查詢
 5             var query = from radius in radii
 6                 select $"{radius * radius * 3.14}";
 7 
 8             //執行查詢
 9             foreach (var i in query)
10             {
11                 Console.WriteLine(i);
12             }
View Code

 

四、LINQ 查詢操作的類型關係

  LINQ 查詢操作在數據源、查詢本身及查詢執行中是強類型的。查詢中變數的類型必須與數據源中元素的類型和 foreach 語句中迭代變數的類型相容。此強類型保證在編譯時捕獲類型錯誤,以便可以在用戶遇到這些錯誤之前更正它們。

 

  4.1 不轉換源數據的查詢

  下圖演示不對數據執行轉換的 LINQ to Objects 查詢操作。源包含一個字元串序列,查詢輸出也是一個字元串序列。 

  (1)數據源的類型參數決定範圍變數的類型。

  (2)選擇的對象的類型決定查詢變數的類型。此處的 name 為一個字元串。因此,查詢變數是一個 IEnumerable<字元串>。  

  (3)在 foreach 語句中迴圈訪問查詢變數。因為查詢變數是一個字元串序列,所以迭代變數也是一個字元串。  

 

  4.2 轉換源數據的查詢

  下圖演示對數據執行簡單轉換的 LINQ to SQL 查詢操作。查詢將一個 Customer 對象序列用作輸入,並只選擇結果中的 Name 屬性。因為 Name 是一個字元串,所以查詢生成一個字元串序列作為輸出。  

  (1)數據源的類型參數決定範圍變數的類型。

  (2)

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 安裝libevent 2. 安裝memcached 3. 安裝memagent 3-1。修改Makefile 3-2。修改ketama.h 3-3.安裝memagent 1 make 2 ln -i /usr/local/magent/magent /usr/bin/magent 4. 使用m ...
  • 1.U-Boot,全稱 Universal Boot Loader,是遵循GPL條款的開放源碼項目。U-Boot的作用是系統引導。U-Boot從FADSROM、8xxROM、PPCBOOT逐步發展演化而來。其源碼目錄、編譯形式與Linux內核很相似,事實上,不少U-Boot源碼就是根據相應的Linu ...
  • ...
  • There are commonly three types of memories in a PIC Microcontroller, Flash Program Memory, Data Memory (RAM) and EEPROM Data Memory. We write Programs... ...
  • Ubuntu 16.04系統在一開始安裝完成時是無法切換到 root 用戶的,普通用戶需要使用 root 許可權的時候通常需要在執行命令前加 "sudo",需要經常使用root許可權的伙伴可能會覺得這會讓我們的蛋蛋同學很憂傷...... 其實,要解決蛋蛋同學的問題很簡單,只要給 root 配一個密碼即可 ...
  • 整理Apache+Mysql+PHP+PHPWind(Apache+PHP集成環境) 一、情況簡述: 1、虛擬機VM上面CentOS 2、全部yum安裝(yum安裝與源碼安裝的安裝路徑不同) 二、操作步驟簡述 安裝Apache(httpd) 安裝Mysql(mysqld) 安裝PHP(phpd-fd ...
  • 使用HttpListener實現簡單的Http服務 HttpListener提供一個簡單的、可通過編程方式控制的 HTTP 協議偵聽器.使用它可以很容易的提供一些Http服務,而無需啟動IIS這類大型服務程式。使用HttpListener的方法流程很簡單:主要分為以下幾步 創建一個HTTP偵聽器對象 ...
  • 頁面設計需求,做了一個氣泡形狀的彈出框,效果如下: 設計思路如下: 1. 使用Path繪製氣泡的尖尖,將這個放到頂層; 2. 在用border繪製長方形框,將這個放到底層,並且設置Margin值,使得Path圖層和border看起來銜接在一起。 代碼如下: 後臺代碼,很簡單,就是控制pupup顯示或 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...