LINQ to Objects系列 4 表示式樹

2021-09-06 15:40:57 字數 4179 閱讀 9679

為了進一步加深對lambda表示式的理解,我們需要掌握乙個新的知識,lambda表示式樹,可能聽名字看起來很高深和難以理解,但實際上理解起來並沒有想象中那麼難,這篇文章我想分以下幾點進行總結。

1,表示式樹的語法

2,將**轉換到資料

3,探索表示式樹

4,將資料轉換到**

5,iqueryable和表示式樹

6,為什麼要將linq to sql查詢表示式轉換成表示式樹?

7,iqueryable和ienumerable

8,總結

//

利用lambda表示式定義乙個func委託

func function = (a, b) => a + b;

變數function指向兩個數字相加的原生可執行的**,上面這個lambda表示式等價於下面這個方法。

public

int function(int a, int

b)

這個lambda表示式和這個方法都可以這樣呼叫。

int c = function(1,2); //

結果為:3

表示式樹不是一段可執行**,而是一種資料結構。那麼怎麼將lambda表示式轉換成表示式樹呢?

我們可以使用命名空間system.linq.expressions下的expression類來實現這個需求。

例如我們先建立乙個表示式樹,如下**。

//

建立表示式樹

expressionint, int, int>> expression = (a, b) => a + b;

這樣,我們就建立乙個型別為expression的表示式樹,標識expression不是可執行**;它是乙個名叫表示式樹的資料結構。我們可以使用工具expressiontreevisualizer來瀏覽表示式樹,如下圖。

expression類有四個屬性:

那麼怎麼檢視表示式樹中的引數名稱呢?從上圖中我們可以看出,引數是乙個readonlycollection集合,所以我們可以通過索引來訪問。如下**。

//

訪問表示式樹的引數

console.writeline("

引數1:,引數2:

",expression.parameters[0],expression.parameters[1]);

接下來,怎麼檢視表示式樹的body體呢?在這個例子裡是(a+b)。**如下。

//

訪問表示式樹的body

binaryexpression body = expression.body as

binaryexpression;

parameterexpression left = body.left as

parameterexpression;

parameterexpression right = body.right as

parameterexpression;

console.writeline(expression.body);

console.writeline(

"表示式左邊部分:

" + "

節點型別: 表示式右邊部分: 型別:

", left.name, body.nodetype, right.name, body.type, environment.newline);

輸出結果為:

通過探索表示式樹,我們可以分析表示式的各個部分發現它的組成。你可以看見,我們的表示式的所有元素都展示為像節點這樣的資料結構。表示式樹是**轉換成的資料。

我們可以將**轉換為資料,那麼我們也可將資料轉換為**。下面的**說明了如果將資料(表示式樹資料結構)轉換為**。

//

將資料(表示式樹)轉換為**

int result = expression.compile()(1,2

);console.writeline(result);

//輸出結果為:3

可以發現,程式輸出結果與lambda表示式執行結果一樣。

現在至少你有乙個抽象的概念理解表示式樹,現在是時候回來理解其在linq中的關鍵作用了,尤其是在linq to sql中。花點時間考慮這個標準的linq to sql查詢表示式:

var query =

from c in

db.customers

where c.city ==

"nantes"

select new ;

你可能知道,這裡linq表示式返回的變數query是iqueryable型別。這裡是iqueryable型別的定義:

public

inte***ce

iqueryable : ienumerable

expression expression

iqueryprovider provider

}

你可以看見,iqueryable包含乙個型別為expression的屬性,expression是expression的基類。iqueryable的例項被設計成擁有乙個相關的表示式樹。它是乙個等同於查詢表示式中的可執行**的資料結構。

現在我們知道,表示式樹是乙個用來表示可執行**的資料結構。那我們為什麼要將linq to sql查詢表示式轉換成表示式樹呢?

乙個linq to sql查詢不是在c#程式裡執行的,而是被轉換成sql語句,通過網路傳送,最後在資料庫伺服器上執行的。也就是說,下面這個linq查詢不是在c#程式裡執行的。

var query =

from c in

db.customers

where c.city ==

"nantes"

select new ;

它是被轉換成sql語句後在資料庫伺服器上執行的。轉換後的sql語句如下**。

select[t0

].[city

], [

t0].[

companyname

]from

[dbo

].[customers]as

[t0]where[t0

].[city]=

@p0

現在也許可以回答上面的問題。可以用一句話總結:表示式樹是為了更方面地將查詢表示式轉換成字串(這裡指的是sql語句)並交給其它程式(這裡一般指資料庫伺服器)執行。

我們知道,linq to objects通常返回ienumerable,而linq to sql返回的是iqueryable。那為什麼它們返回的型別會不一樣呢?

我們先來看它們的定義,也許我們可以從它們的定義中找到問題的答案。

ienumberable的定義如下:

public

inte***ce ienumerable: ienumerable

iqueryable的定義如下:

public

inte***ce

iqueryable : ienumerable

expression expression //

表示式樹

iqueryprovider provider

}

可以看出,iqueryable包含乙個expression表示式樹的定義而ienumberable卻沒有,這同時也揭示了乙個現象,表示式樹通常用在linq to sql查詢中,而linq to objects中卻很少使用。

那為什麼linq to objects中很少使用表示式樹呢?是因為linq to objects查詢通常在.net程式中就可以完成,不需要將其轉換成字串(或sql語句)傳送到其它程式中執行。

那麼針對這兩種返回型別,我們該怎麼選擇呢?這裡有兩條原則可以參考:

通過以上內容的學習,發現表示式樹並沒有想象中那麼難以理解,關於表示式樹我想用以一幾句通俗易懂的話總結。

表示式樹是一種用來表示可執行**(一般指lambda查詢表示式)的樹形資料結構。

表示式樹在linq to sql中使用得非常多(因為linq to sql查詢返回iqueryable型別),通過表示式樹,linq to sql查詢表示式更方便地被解析成sql語句併發送到資料庫伺服器上執行。

一條最佳實踐原則:linq查詢如果在程式內執行的不需要表示式樹,當**在程式外部執行時則需要使用表示式樹。

LINQ To Objects 的資料來源

linq to objects的資料來源 文 黃忠成 在 linq to objects 的架構中,只要實作了 ienumerable 介面的物件,皆可做為 linq to objects 的資料來源,那具體有那些呢?見下表。型別 說明 ienumerable 系列 1 具型陣列,如 string ...

python系列教程 python系列教程

宣告 在人工智慧技術教學期間,不少學生向我提一些python相關的問題,所以為了讓同學們掌握更多擴充套件知識更好的理解人工智慧技術,我讓助理負責分享這套python系列教程,希望能幫到大家!由於這套python教程不是要由所寫,所以不如我的人工智慧技術教學風趣幽默,學起來比較枯燥 但它的知識點還是講...

系列 探囊取物

一整個晚上jack幾乎都沒有閒著,除了與目標人物天南海北的談天以推延之間之外,jack緊張地通過beast遠端控制 在對方計算機上尋找著證據。jack 不過這個壓縮包處於加密狀態,jack無法讀取其中的資訊,看來必須破解其密碼才行嘍。jack的家2006.1.18 星期三01 45 而讓jack感到...