天天看點

表達式樹的解析.

公司的orm架構在dapper的基礎上擴充了一套表達式的方法,當時就研究了一下,把學習過程和結果記錄下來,和大家分享。

有人會說重複造輪子沒必要,直接上EF。

從我的角度來看重複造輪子的原因有以下三種:

1、研究造輪子的原理

2、輪子不滿足現在的開發需要

3、裝B

最常用到的無非就是ORM的删查改的條件,ORM就是在ado.Net的基礎上封裝了一層表達式,最後還是将表達式解析成sql,由ado.Net去執行。

那麼我們能将表達式樹解析成字元串,那麼也能反過來。例如運費系統,在背景設定定義好一套計算規則。例如:對應不同的發貨管道,什麼重量取哪個區間的費用,多于哪個階段的費用還要額外費用。我們可以通過解析這套計算規則拼裝好表達式樹傳入參數進行計算。。。

還有别的在評論補充下。。。

不扯多,現在我們隻拿解析表達式樹來學習。

首先建立4個屬性的Users類

表達式樹的解析.
表達式樹的解析.

View Code

接着,我們從最簡單的開始,寫一個二進制運算表達式,F5調試監控觀察。

表達式樹的解析.

從上圖可以看見有很多屬性,在表達式主體(屬性Body),我們暫時隻關注三個屬性,Left(左節點)、Right(右節點)和 NodeType (目前節點類型)

表達式樹的解析.

表達式主體(users.Name == "SkyChen")是一個二進制運算表達式,是以可以将Body轉換成 BinaryExpression 類型來通路Left和Right。

Left 和 Right 的 NodeType 分别為 MemberAccess(從字段或屬性進行讀取的運算)、Constant(常量)。

是以可以将 Left 轉換成 MemberExpression 類型來通路 Member 屬性,将 Right 轉換成 ConstantExpression 類型來通路 Value 屬性。具體代碼如下:

表達式樹的解析.
表達式樹的解析.

TransferExpressionType 是針對部分 ExpressionType 的一個轉換。

表達式樹的解析.
表達式樹的解析.

那麼。一個最簡單的表達式解析成where語句就完成了。

表達式樹的解析.

然而,實踐工作中,大家都會寫相對複雜或者說多個條件的表達式。那麼再采用上面的方式是無法确認表達式節點的類型進行轉換的。我們可以添加一個Visit方法,根據 NodeType 轉換成對應的Expression的類型,進而方法通路對應的屬性進行表達式解析。

但是,重寫之前,我們得了解一件事,既然叫表達式樹,意味着在子節點裡,還會有多個節點,如下圖:

表達式樹的解析.

那麼,我們假設,隻要是 BinaryExpression(二進制運算表達式)就會有多個子節,去通路子節點就是一個遞歸的過程,而終點就是 MemberExpression  和 ConstantExpression,對應字段名稱和常量值的拼接。

下面是代碼實作:

表達式樹的解析.
表達式樹的解析.

 結果如下:

表達式樹的解析.

一個基本的表達式解析思路基本實作了,但是!随着自己的orm的完善是不是這麼多種的Expression類型都得在Visit方法添一遍,不是的。

ExpressionVisitor類是提供給我們的表達式樹解析的幫助類,我們隻要定義一個類繼承ExpressionVisitor,實作一個 ResolveExpression 入口方法,重寫

VisitBinary、VisitConstant、VisitMember方法,代碼如下:

表達式樹的解析.
表達式樹的解析.

一個簡單的表達式解析大緻完成了,當然裡面還有很多可以完善,例如值類型的判斷,is 還是 = ,VisitMethodCall重寫等等。原理就這樣,實作我這裡就不一一列舉。如對大家有幫助,麻煩請推薦,有不足請在下面評論提出,我會一一更改。

作  者:

陳珙

出  處:http://www.cnblogs.com/skychen1218/

關于作者:專注于微軟平台的項目開發。如有問題或建議,請多多賜教!

版權聲明:本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連結。

聲援部落客:如果您覺得文章對您有幫助,可以點選文章右下角推薦一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!