Linq的基本用法
Linq,語言內建查詢(language intergrated query)是一組用于C#的擴充。使用Linq可以對集合等記憶體資料進行查詢,還可以查詢資料庫(datebase)、XML(标準通用标記語言)資料,分别稱為Linq to object,Linq to datebase和Linq to XML。這裡談的是Linq to object。
Linq的寫法類似于資料庫SQL語句的查詢文法。
from 變量名 in 集合 where 條件 select 結果變量
其中,變量名是一個臨時變量,集合是數組或其他集合對象,條件一般是一個針對變量的邏輯表達式,而結果變量一般是針對變量名的表達式(可以是變量自己)。例如:
表示從數組
arr
中找到大于5的元素(
n
),并且最終選出這些
n
。
如果是選出這些數的平方,則是:
針對滿足條件的數,還可以先進行降序排序,然後再輸出結果,如:
示例1
查詢
int
數組中大于的數字,并按照大小順序排列:
static void Main(string[] args) {
Random rnd = new Random();
// 示例1,查詢int數組中大于10的數字,并按照大小順序排列:
int[] arr = new int[20];
for (int i = 0; i < arr.Length; i++) arr[i] = rnd.Next(20);
var m = from n in arr where n > 10 orderby n descending select n;
foreach (var n in m)
Console.Write(n + " ");
Console.WriteLine();
}
運作結果:

從上面的例子可以看到,
Linq
查詢文法跟SQL查詢文法很相似,但它要将
from
放到前面,這樣變量的類型才好推斷,友善內建開發環境進行智能感覺(intellisence)。
Linq
查詢的結果傳回的是一個枚舉器對象,實作了
IEnumerable
接口,這個對象的類型一般很複雜,用
var
類型來表示,讓編譯器自動推斷其類型。這個
var
對象可以用
foreach
來進行周遊。有的
Linq
查詢傳回的結果是“可查詢對象”,實作
IQuerable
接口,由于
IQuerable
接口是
IEnumerable
接口的子接口,可以對它進行更複雜的操作。
值得注意的是:這個枚舉器
var
對象并沒有開始執行真正的查詢,隻有當用
foreach
來進行周遊時,查詢過程才真正地執行。
示例2
一個稍微複雜的Linq查詢,使用group分組功能:
static void Main(string[] args) {
// 示例2,一個稍微複雜的Linq查詢,使用group分組功能:
string[] languages = { "Java", "C#", "C++", "Delphi", "VB.net", "VC.net", "Perl", "Python" };
var query = from item in languages
group item by item.Length into lengthGroups
orderby lengthGroups.Key
select lengthGroups;
foreach (var group in query) {
Console.WriteLine("strings of length{0}", group.Key);
foreach (var str in group) {
Console.WriteLine(str);
}
}
}
運作結果:
在這個例子中,按照字元長短(
length
)對資料進行分組(
group
)并放入
lengthGroups
變量中,按分組的關鍵字(
.Key
)進行排序。所得到的枚舉器用雙重的
foreach
循環進行周遊。
Linq的查詢方法
Linq定義了大約40個查詢操作符,如
select
、
from
、
in
、
where
以及
orderby
等。
1.Linq的兩種寫法
一種形式是查詢表達式文法(query expression syntax),另一種更接近SQL文法的查詢方式,可讀性更好。
另一種形式是查詢方法文法(method syntax),主要利用
System.Linq.Enumerable
類中定義的擴充方法和Lambda表達式方法進行查詢。例如:
List<int> arr = new List<int>() { 1, 2, 3, 4, 5, 6, 7 };
var result = arr.Where(a => a > 3).Sum();
Console.WriteLine(result);
這段代碼中,用到了兩個擴充方法。
一個是
Where
擴充方法,需要傳入一個
Func<int, bool>
類型的泛型委托,它表示對一個元素(
int
類型的變量)進行判斷(
a > 3
),傳回值是
bool
類型。這裡是直接把
a => a > 3
這個Lambda表達式傳遞給了
Where
方法。
另一個是
Sum
擴充方法,它計算了
Where
擴充方法傳回的集合的和。
使用
where
等子句,實際上是調用了
Enumerable
類中定義的擴充方法。
2.擴充方法
這裡所謂的“擴充方法(extension methods)”是在
static
的類中定義的全局函數,它可以帶
this
參數,表示對某種對象上施加以一個方法,編譯器會自動地将它轉成對擴充方法的調用。
示例
對String的擴充方法:
using System;
public static class ExtensionMethodString
{
public static int WordCount(this string s) {
string[] words = s.Split(" ,;.!".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
return words.Length;
}
}
class Demo
{
static void Main(string[] args){
string s = "Hello world,C#!";
int cnt = s.WordCount();
Console.WriteLine(cnt);
}
}
output:
3
在這裡,對
string
對象進行了擴充,添加了
WordCount
方法,但是不是在
string
類的内部添加的,而是單獨定義了一個
static
類
ExtensionMethodString
,其中定義了
static
方法
WordCount
,其第一個參數(
string
類型)前面加了個特殊的this,進而表明它是一個特殊的對
string
類型的擴充方法。編譯器會将
s.WordCount()
自動翻譯成
ExtensionMethodString.WordCount
調用。
擴充方法是一個很有用的機制,它在不改變原類的定義的情況下,給原來“添加”了一個方法,實際上是一種文法糖。
擴充方法是從C#3.0 開始引入的,它的作用之一就是為Linq服務的。在Linq技術上,.NET的設計者在類庫中定義了一系列的擴充方法來友善使用者操作集合對象,這些擴充方法構成了Linq的查詢操作符。
3.Linq的查詢運算符
Linq的各種查詢運算符實際上是定義在
System.Linq.Enumerable
等類中的一系列擴充方法,這些擴充方法是對
IEnumerable
等對象的擴充。是以可以用
var result = arr.Where(a => a > 3).Sum()
這樣的調用方法來進行調用。
Linq的标準查詢運算符有多達40多個,如下表。這些方法中有一小部分可以有等價的查詢表達式關鍵字,如
where
關鍵字等價于
Where
方法,類似的還有
select
,
group
,
orderby
,
join
等。
從執行時間上來看,各個标準查詢運算符可以分為兩類,一類是立即執行,一類是延遲執行。傳回單一值的方法(如
Average
和
Sum
)會立即執行。而傳回序列的方法會延遲查詢執行,因為它傳回一個可枚舉(
IEnumerable
)的對象,隻有當用
foreach
進行周遊或者再次施以
Sum
等操作時才會真正執行。也可以說,查詢運算符分兩類,一類是“中間點”(如
Where
),它可以繼續施加其他查詢運算符;一類是“結束的”(如
Sum
),它的結果不能再施加其他查詢運算符。
下面是常用運算符及其簡單介紹:
Where:過濾出滿足條件的。
Select:取出元素(可以映射到新的對象)。
First:取出序列第一個元素。
Take:取出部分元素。
Single:取出序列的唯一一個元素,如果元素個數不是1個,則報錯。
FirstOrDefault:取得序列第一個元素,如果沒有一個元素,則傳回預設值。
Distinct:取出序列中非重複元素。
Orderby:排序。
Reverse:反序。
Concat:連接配接兩個序列;相當于SQL的Union all。
Contains:序列是否包含指定元素。
Except:獲得兩個序列的差集。
Intersect:獲得兩個序列的交集。
Average:計算平均值。
Min:最小元素。
Max:最大元素。
Sum:元素總和。
Count:元素數量。