共享一个从字符串转 Lambda 表达式的类(4)
開始寫第四篇,別的不說了。這篇將涉及到如何使用字符串解析結(jié)果,生成一個 Lambda 表達式樹。東西有點多,我先整理一下思路,在下面說明一下。如果你有問題,在后面的評論上寫下來,我看到了會回復(fù)你。
?
?
在前幾篇中,我寫了一個字符串解析模塊,還有一個根據(jù)字符串解析成 Type 對象的類型分析模塊。這兩個模塊,都將為這個 Expression 核心解析類提供輔助,所以如果前兩篇文章你沒有看到,可以到我博客中先把前幾篇文章看一下,理解我的整體思路后,再回過頭來看這篇。
?
我希望從這篇文章開始,看到一些有用的評論,謝謝了!
?
?
Expression 核心解析類(ExpressionParserCore)對外發(fā)布的只有一個方法 —— ToLambdaExpression ,用于輸出分析得到的 Lambda 表達式樹。在貼代碼之前,我把大致思路說明一下:
?
?
首先,需要幾個前提條件:
1.? 待分析的字符串
2.? Lambda 表達式樹包含的委托類型
3.? 類型解析可能用到的命名空間和程序集列表
?
第一個,很好理解,在這里不做闡述。
第二個,是告訴要解析的目標(biāo)參數(shù)和返回值信息。
第三個,類型解析中會用到,這里只是做一下參數(shù)傳遞。具體的代碼可以參看第三篇。
?
?
其次,由于 Lambda 表達式樹的遞歸特性,所以其解析工作不可能一蹴而就,所以解析工作將其拆分為三步:
1.? ReadFirstExpression
2.? ReadNextExpression
3.? ReadExpression
?
從字面上可以看出來:ReadFirstExpression 是讀取第一個 Expression ,ReadNextExpression 是讀取接下來的 Expression ,ReadExpression 是讀取 Expression 。
?
?
ReadFirstExpression:讀取第一個 Expression ,不去管后面是不是還有沒有解析的 Expression 。比如:【() => 1 + 2】這個表達式,如果使用該方法則只會讀取常量表達式【1】,不會繼續(xù)讀取剩下的常量表達式【2】和加法表達式。一句話總結(jié):讀取了一個 Expression 就停止讀取。
?
?
ReadNextExpression:讀取下一個 Expression ,在已讀取了表達式的基礎(chǔ)上繼續(xù)解析 Expression 。接著上面的表達式【() => 1 + 2】繼續(xù)說,讀取了表達式【1】后,繼續(xù)讀取常量表達式【2】,再繼續(xù)讀取加法表達式,返回整個表達式。
?
到了這里,有人會問:為什么會分成讀取第一個和讀取下一個兩個方法?有以下原因吧,我感覺分開好些:
1.? 有些表達式不能作為第一個表達式(比如加法表達式),有些不能作為后續(xù)的表達式(比如求反表達式)。
2.? 就是有些符號不能在開始表達式中(比如右括號),有些不能作為在結(jié)束表達式中(比如左括號)。
3.? 開始表達式從零構(gòu)造一個表達式,后續(xù)表達式需要一個前置表達式。
還有一些,暫時想到的就這些了。
?
?
ReadExpression:讀取表達式,可以遞歸調(diào)用實現(xiàn) Expression 的遞歸。在發(fā)布的方法 ToLambdaExpression 中,調(diào)用的就是 ReadExpression ,進行第一次的遞歸操作。在表達式中如果需要,可能會多次調(diào)用,比如表達式【() => 1 + 2】會調(diào)用兩次:一次是開始調(diào)用 ToLambdaExpression 的時候,一次是解析常量表達式【2】的時候。
?
在此,我把大概的流程用【() => 1 + 2】說明一下吧:
1.? 準(zhǔn)備前提條件。
2.? 將字符串【() => 1 + 2】解析為我們需要的 Token 單元集合。
3.? 分析目標(biāo)委托類型(可以理解為 typeof(Func<int>).GetType() )為 0 個參數(shù),返回值為 int 的委托。
4.? 調(diào)用 ToLambdaExpression 開始解析 Lambda 表達式樹:第一次調(diào)用 ReadExpression 方法。
5.? ReadExpression 方法調(diào)用 ReadFirstExpression 方法獲取一個常量表達式樹【1】。
6.? ReadExpression 方法繼續(xù)調(diào)用 ReadNextExpression 方法,并傳遞參數(shù)常量表達式樹【1】。
7.? 讀取到加法表達式樹,將常量表達式樹【1】作為加法左邊的表達式樹,尚需要的右邊表達式樹,調(diào)用 ReadExpression 方法讀取。
8.? ReadExpression 方法調(diào)用 ReadFirstExpression 方法獲取一個常量表達式樹【2】。
9.? ReadExpression 方法繼續(xù)調(diào)用 ReadNextExpression 方法,并傳遞參數(shù)常量表達式樹【2】。
10. 發(fā)現(xiàn)已經(jīng)讀取到末尾,ReadNextExpression 方法返回傳遞進來的參數(shù)常量表達式樹【2】。
11. ReadExpression 返回讀取到的常量表達式【2】,這里將返回到第 7 步。
12. 加法表達式的左右表達式均已具備,構(gòu)造加法表達式【1 + 2】,并返回到第 6 步。
13. 繼續(xù)讀取發(fā)現(xiàn)讀取到末尾,返回加法表達式【1 + 2】到第 4 步。
14. 根據(jù)委托類型構(gòu)造 Lambda 表達式樹并返回,解析完成。
?
我先將這三個方法的原型說明一下:
1.? ReadFirstExpression()
2.? ReadNextExpression(int level, ReadResult previousResult, TokenId? wrapStart = null)
3.? ReadExpression(int level = 0)
?
level???????? : 這個參數(shù)是運算符優(yōu)先級,優(yōu)先級越大該數(shù)字越大,比如【1 + 2 * 3】這個表達式,會先進行【2 * 3】的組合而不是【1 + 2】的組合。
previousResult: 表示前面分析得到的結(jié)果。包含兩個屬性:表達式和是否讀取結(jié)束。
wrapStart???? : 表示讀取下一個表達式的前導(dǎo) Token 類型。previousResult 中的屬性【是否讀取結(jié)束】和這個參數(shù)相關(guān):每種括號的開始和結(jié)束對應(yīng)。
?
?
就到這里吧,寫太長了,估計多數(shù)人沒看下去的興趣。下篇我會把 ReadFirstExpression 方法的邏輯整理一下,順便貼出來部分代碼。如果你感覺我寫的東西有用,或者你期待下一篇,請點一下推薦,謝謝了!
轉(zhuǎn)載于:https://www.cnblogs.com/lenic/archive/2012/06/26/2563559.html
總結(jié)
以上是生活随笔為你收集整理的共享一个从字符串转 Lambda 表达式的类(4)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C笔记
- 下一篇: 在Linux下使用screen使用退出远