国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

LINQ to Objects系列(4)表達(dá)式樹(shù)

2019-11-17 03:09:31
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

LINQ to Objects系列(4)表達(dá)式樹(shù)

  為了進(jìn)一步加深對(duì)Lambda表達(dá)式的理解,我們需要掌握一個(gè)新的知識(shí),Lambda表達(dá)式樹(shù),可能聽(tīng)名字看起來(lái)很高深和難以理解,但實(shí)際上理解起來(lái)并沒(méi)有想象中那么難,這篇文章我想分以下幾點(diǎn)進(jìn)行總結(jié)。

1,表達(dá)式樹(shù)的語(yǔ)法

2,將代碼轉(zhuǎn)換到數(shù)據(jù)

3,探索表達(dá)式樹(shù)

4,將數(shù)據(jù)轉(zhuǎn)換到代碼

5,IQueryable<T>和表達(dá)式樹(shù)

6,為什么要將LINQ to SQL查詢表達(dá)式轉(zhuǎn)換成表達(dá)式樹(shù)?

7,IQueryable<T>和IEnumerable<T>

8,總結(jié)

表達(dá)式樹(shù)的語(yǔ)法

//利用Lambda表達(dá)式定義一個(gè)Func委托Func<int, int, int> function = (a, b) => a + b;

變量function指向兩個(gè)數(shù)字相加的原生可執(zhí)行的代碼,上面這個(gè)Lambda表達(dá)式等價(jià)于下面這個(gè)方法。

public int function(int a, int b){    return a + b;}

這個(gè)Lambda表達(dá)式和這個(gè)方法都可以這樣調(diào)用。

int c = function(1,2); //結(jié)果為:3

將代碼轉(zhuǎn)換到數(shù)據(jù)

表達(dá)式樹(shù)不是一段可執(zhí)行代碼,而是一種數(shù)據(jù)結(jié)構(gòu)。那么怎么將Lambda表達(dá)式轉(zhuǎn)換成表達(dá)式樹(shù)呢?

我們可以使用命名空間System.Linq.ExPRessions下的Expression類(lèi)來(lái)實(shí)現(xiàn)這個(gè)需求。

例如我們先創(chuàng)建一個(gè)表達(dá)式樹(shù),如下代碼。

//創(chuàng)建表達(dá)式樹(shù)Expression<Func<int, int, int>> expression = (a, b) => a + b;

這樣,我們就創(chuàng)建一個(gè)類(lèi)型為Expression<T>的表達(dá)式樹(shù),標(biāo)識(shí)expression不是可執(zhí)行代碼;它是一個(gè)名叫表達(dá)式樹(shù)的數(shù)據(jù)結(jié)構(gòu)。我們可以使用工具ExpressionTreeVisualizer來(lái)瀏覽表達(dá)式樹(shù),如下圖。

ExpressionTree

探索表達(dá)式樹(shù)

Expression<TDelegate>類(lèi)有四個(gè)屬性:

  • Body: 得到表達(dá)式的主體。
  • Parameters: 得到lambda表達(dá)式的參數(shù).
  • NodeType: 獲取樹(shù)的節(jié)點(diǎn)的ExpressionType。共45種不同值,包含所有表達(dá)式節(jié)點(diǎn)各種可能的類(lèi)型,例如返回常量,例如返回參數(shù),例如取兩個(gè)值的小值(<),例如取兩個(gè)值的大值(>),例如將值相加(+),等等。
  • Type: 獲取表達(dá)式的一個(gè)靜態(tài)類(lèi)型。在這個(gè)例子里,表達(dá)式的類(lèi)型是Func<int,int,int>。

那么怎么查看表達(dá)式樹(shù)中的參數(shù)名稱呢?從上圖中我們可以看出,參數(shù)是一個(gè)ReadOnlyCollection集合,所以我們可以通過(guò)索引來(lái)訪問(wèn)。如下代碼。

//訪問(wèn)表達(dá)式樹(shù)的參數(shù)Console.WriteLine("參數(shù)1:{0},參數(shù)2:{1}",expression.Parameters[0],expression.Parameters[1]);

接下來(lái),怎么查看表達(dá)式樹(shù)的Body體呢?在這個(gè)例子里是(a+b)。代碼如下。

//訪問(wèn)表達(dá)式樹(shù)的BodyBinaryExpression body = expression.Body as BinaryExpression;ParameterExpression left = body.Left as ParameterExpression;ParameterExpression right = body.Right as ParameterExpression;Console.WriteLine(expression.Body);Console.WriteLine(" 表達(dá)式左邊部分: " + "{0}{4} 節(jié)點(diǎn)類(lèi)型: {1}{4} 表達(dá)式右邊部分: {2}{4} 類(lèi)型: {3}{4}", left.Name, body.NodeType, right.Name, body.Type, Environment.NewLine);

輸出結(jié)果為:

通過(guò)探索表達(dá)式樹(shù),我們可以分析表達(dá)式的各個(gè)部分發(fā)現(xiàn)它的組成。你可以看見(jiàn),我們的表達(dá)式的所有元素都展示為像節(jié)點(diǎn)這樣的數(shù)據(jù)結(jié)構(gòu)。表達(dá)式樹(shù)是代碼轉(zhuǎn)換成的數(shù)據(jù)。

將數(shù)據(jù)轉(zhuǎn)換到代碼

我們可以將代碼轉(zhuǎn)換為數(shù)據(jù),那么我們也可將數(shù)據(jù)轉(zhuǎn)換為代碼。下面的代碼說(shuō)明了如果將數(shù)據(jù)(表達(dá)式樹(shù)數(shù)據(jù)結(jié)構(gòu))轉(zhuǎn)換為代碼。

//將數(shù)據(jù)(表達(dá)式樹(shù))轉(zhuǎn)換為代碼int result = expression.Compile()(1,2);Console.WriteLine(result); //輸出結(jié)果為:3

可以發(fā)現(xiàn),程序輸出結(jié)果與Lambda表達(dá)式執(zhí)行結(jié)果一樣。

IQueryable<T>和表達(dá)式樹(shù)

現(xiàn)在至少你有一個(gè)抽象的概念理解表達(dá)式樹(shù),現(xiàn)在是時(shí)候回來(lái)理解其在LINQ中的關(guān)鍵作用了,尤其是在LINQ to SQL中。花點(diǎn)時(shí)間考慮這個(gè)標(biāo)準(zhǔn)的LINQ to SQL查詢表達(dá)式:

var query = from c in db.Customers             where c.City == "Nantes"             select new { c.City, c.CompanyName };

你可能知道,這里L(fēng)INQ表達(dá)式返回的變量query是IQueryable類(lèi)型。這里是IQueryable類(lèi)型的定義:

public interface IQueryable : IEnumerable {  Type ElementType { get; }  Expression Expression { get; }  IQueryProvider Provider { get; }}

你可以看見(jiàn),IQueryable包含一個(gè)類(lèi)型為Expression的屬性,Expression是Expression<T>的基類(lèi)。IQueryable的實(shí)例被設(shè)計(jì)成擁有一個(gè)相關(guān)的表達(dá)式樹(shù)。它是一個(gè)等同于查詢表達(dá)式中的可執(zhí)行代碼的數(shù)據(jù)結(jié)構(gòu)。

為什么要將LINQ to SQL查詢表達(dá)式轉(zhuǎn)換成表達(dá)式樹(shù)?

現(xiàn)在我們知道,表達(dá)式樹(shù)是一個(gè)用來(lái)表示可執(zhí)行代碼的數(shù)據(jù)結(jié)構(gòu)。那我們?yōu)槭裁匆獙INQ to SQL查詢表達(dá)式轉(zhuǎn)換成表達(dá)式樹(shù)呢?

一個(gè)LINQ to SQL查詢不是在C#程序里執(zhí)行的,而是被轉(zhuǎn)換成SQL語(yǔ)句,通過(guò)網(wǎng)絡(luò)發(fā)送,最后在數(shù)據(jù)庫(kù)服務(wù)器上執(zhí)行的。也就是說(shuō),下面這個(gè)LINQ查詢不是在C#程序里執(zhí)行的。

var query = from c in db.Customers            where c.City == "Nantes"            select new { c.City, c.CompanyName };

它是被轉(zhuǎn)換成SQL語(yǔ)句后在數(shù)據(jù)庫(kù)服務(wù)器上運(yùn)行的。轉(zhuǎn)換后的SQL語(yǔ)句如下代碼。

SELECT [t0].[City], [t0].[CompanyName]FROM [dbo].[Customers] AS [t0] WHERE [t0].[City] = @p0

現(xiàn)在也許可以回答上面的問(wèn)題。可以用一句話總結(jié):表達(dá)式樹(shù)是為了更方面地將查詢表達(dá)式轉(zhuǎn)換成字符串(這里指的是SQL語(yǔ)句)并交給其它程序(這里一般指數(shù)據(jù)庫(kù)服務(wù)器)執(zhí)行。

IQueryable<T>和IEnumerable<T>

我們知道,LINQ to Objects通常返回IEnumerable<T>,而LINQ to SQL返回的是IQueryable<T>。那為什么它們返回的類(lèi)型會(huì)不一樣呢?

我們先來(lái)看它們的定義,也許我們可以從它們的定義中找到問(wèn)題的答案。

IEnumberable<T>的定義如下:

public interface IEnumerable<T> : IEnumerable {    IEnumerator<T> GetEnumerator();}

IQueryable<T>的定義如下:

public interface IQueryable : IEnumerable {  Type ElementType { get; }  Expression Expression { get; } //表達(dá)式樹(shù)  IQueryProvider Provider { get; }}

可以看出,IQueryable<T>包含一個(gè)Expression表達(dá)式樹(shù)的定義而IEnumberable<T>卻沒(méi)有,這同時(shí)也揭示了一個(gè)現(xiàn)象,表達(dá)式樹(shù)通常用在LINQ to SQL查詢中,而LINQ to Objects中卻很少使用。

那為什么LINQ to Objects中很少使用表達(dá)式樹(shù)呢?是因?yàn)長(zhǎng)INQ to Objects查詢通常在.net程序中就可以完成,不需要將其轉(zhuǎn)換成字符串(或SQL語(yǔ)句)發(fā)送到其它程序中執(zhí)行。

那么針對(duì)這兩種返回類(lèi)型,我們?cè)撛趺催x擇呢?這里有兩條原則可以參考:

  • 如果查詢表達(dá)式可以在本程序里執(zhí)行的,那么使用Enumberable<T>就可以完成任務(wù)。
  • 如果查詢表達(dá)式需要被轉(zhuǎn)換成字符串并發(fā)送到其它程序中執(zhí)行的,那么就應(yīng)該使用IQueryable<T>和表達(dá)式樹(shù)。

總結(jié)

通過(guò)以上內(nèi)容的學(xué)習(xí),發(fā)現(xiàn)表達(dá)式樹(shù)并沒(méi)有想象中那么難以理解,關(guān)于表達(dá)式樹(shù)我想用以一幾句通俗易懂的話總結(jié)。

  1. 表達(dá)式樹(shù)是一種用來(lái)表示可執(zhí)行代碼(一般指Lambda查詢表達(dá)式)的樹(shù)形數(shù)據(jù)結(jié)構(gòu)。
  2. 表達(dá)式樹(shù)在LINQ to SQL中使用得非常多(因?yàn)長(zhǎng)INQ to SQL查詢返回IQueryable<T>類(lèi)型),通過(guò)表達(dá)式樹(shù),LINQ to SQL查詢表達(dá)式更方便地被解析成SQL語(yǔ)句并發(fā)送到數(shù)據(jù)庫(kù)服務(wù)器上執(zhí)行。
  3. 一條最佳實(shí)踐原則:LINQ查詢?nèi)绻诔绦騼?nèi)執(zhí)行的不需要表達(dá)式樹(shù),當(dāng)代碼在程序外部執(zhí)行時(shí)則需要使用表達(dá)式樹(shù)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 兰考县| 平泉县| 浮山县| 繁昌县| 措勤县| 新民市| 南城县| 卫辉市| 突泉县| 泸水县| 忻州市| 云和县| 宁明县| 梧州市| 都匀市| 海原县| 班玛县| 固阳县| 正蓝旗| 佛山市| 五大连池市| 大港区| 仁布县| 嘉兴市| 广灵县| 东丰县| 江川县| 莱州市| 东光县| 满洲里市| 积石山| 凯里市| 琼结县| 连云港市| 博兴县| 东丽区| 余干县| 汉中市| 新乐市| 镶黄旗| 如东县|