表達式樹狀結構是定義程式代碼的數據結構。 表達式樹狀架構是以編譯程式用來分析程式代碼併產生編譯輸出的相同結構為基礎。 當您閱讀本文時,您會注意到表達式樹狀架構與 Roslyn API 中用來建置 分析器和程式碼修正的類型之間相當相似。 (分析器和程式代碼修正是 NuGet 套件,可在程式代碼上執行靜態分析,並建議開發人員的潛在修正程式。概念很類似,而最終結果是數據結構,允許以有意義的方式檢查原始程式碼。 不過,表達式樹狀架構是以與 Roslyn API 不同的類別和 API 集合為基礎。 以下是一行程式代碼:
var sum = 1 + 2;
如果您將上述程式代碼分析為表達式樹狀結構,樹狀結構會包含數個節點。 最外層節點是具有指派的變數宣告語句 (var sum = 1 + 2;
) 最外層節點包含數個子節點:變數宣告、指派運算符,以及代表等號右邊的表達式。 該表達式會進一步細分為表示加法運算的表達式,以及加法的左右作數。
讓我們更深入分析等號右側的表達式。 表達式為 1 + 2
,是二進位表達式。 更具體來說,它是二進位加法表達式。 二進位加法表示式有兩個子系,代表加法表達式的左右節點。 在這裡,這兩個節點都是常數表達式:左作數是值 1
,而右作數是值 2
。
以可視化方式,整個語句是樹狀結構:您可以從根節點開始,並移至樹狀結構中的每個節點,以查看構成語句的程序代碼:
- 具有指派的變數宣告語句 (
var sum = 1 + 2;
)- 隱含變數類型宣告 (
var sum
)- 隱含 var 關鍵詞 (
var
) - 變數名稱宣告 (
sum
)
- 隱含 var 關鍵詞 (
- 賦值運算子(
=
) - 二進位加法表示式 (
1 + 2
)- 左運算元(
1
) - 加法運算子 (
+
) - 右運算元(
2
)
- 左運算元(
- 隱含變數類型宣告 (
上述樹狀結構看起來可能很複雜,但它非常強大。 遵循相同的程式,您會分解更複雜的表達式。 請考慮此表示式:
var finalAnswer = this.SecretSauceFunction(
currentState.createInterimResult(), currentState.createSecondValue(1, 2),
decisionServer.considerFinalOptions("hello")) +
MoreSecretSauce('A', DateTime.Now, true);
上述表達式也是具有指派的變數宣告。 在此實例中,指派的右側是更複雜的樹狀結構。 您不會分解此表示式,但請考慮不同的節點可能是什麼。 有方法呼叫使用目前的物件作為接收者,有一個具有明確的 this
接收者,另一個則沒有。 有方法呼叫使用其他接收者物件,有不同類型的常數自變數。 最後,還有二元加法運算符。 根據SecretSauceFunction()
或MoreSecretSauce()
的傳回型別,該二元加法運算符可能是覆寫的加法運算符方法呼叫,並解析為定義在類別上的二元加法運算符靜態方法呼叫。
儘管看起來很複雜,但上述表達式會建立一個樹狀結構,可以像第一個範例一樣輕鬆地巡覽。 您會繼續遍歷子節點,以尋找表達式中的葉子節點。 父節點具有其子節點的引用,而且每個節點都有屬性,描述其節點類型。
表達式樹狀結構非常一致。 瞭解基本概念之後,您甚至可以瞭解最複雜的程式代碼,當程式代碼以表達式樹狀結構表示時。 數據結構中的優雅說明 C# 編譯程式如何分析最複雜的 C# 程式,並從該複雜的原始程式碼建立適當的輸出。
一旦您熟悉表達式樹狀結構,您會發現您快速獲得的知識可讓您使用更多進階案例。 表達式樹具有不可思議的力量。
除了將演算法轉譯成在其他環境中執行之外,表達式樹狀架構可讓您更輕鬆地撰寫演算法,以在執行程式碼之前先檢查程序代碼。 您可以撰寫方法,其自變數為表達式,然後在執行程序代碼之前先檢查這些表達式。 表達式樹狀結構是程式代碼的完整表示法:您會看到任何子表達式的值。 您可以看到方法名稱和屬性名稱。 您會看到任何常數表達式的值。 您可以將表達式樹狀結構轉換成可執行的委派,然後執行程序代碼。
表達式樹狀架構的 API 可讓您建立幾乎代表任何有效程式代碼建構的樹狀結構。 不過,為了讓事情保持盡可能的簡單,有些 C# 慣用語無法在表達式樹中創建。 其中一個範例是異步表達式(使用 async
和 await
關鍵詞)。 如果您的需求需要非同步演算法,您必須直接操作 Task
物件,而不是依賴編譯器支援。 另一個是建立迴圈。 一般而言,您可以使用 for
、foreach
、while
或 do
循環來建立這些迴圈。 如您稍後在此系列中所見,表達式樹狀架構的 API 支援單一循環表達式,以及break
continue
可控制重複循環的表達式。
您無法執行的其中一件事是修改表達式樹狀結構。 表達式樹狀結構是不可變的數據結構。 如果您想要變動(變更)表達式樹狀結構,您必須建立一個新的樹狀結構,此樹狀結構是原始樹的複本,但包含您想要的變更。