運算式樹狀架構 - 定義程式碼的資料

運算式樹狀架構是一種定義程式碼的資料結構。 運算式樹狀架構所依據的結構,與編譯器分析程式碼和產生編譯輸出所使用的結構相同。 當您閱讀本文章時,您將會發現運算式樹狀架構與 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)
    • 指派運算子 (=)
    • 二元加法運算式 (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# 慣用語。 其中一個範例是非同步運算式 (使用 asyncawait 關鍵字)。 如果您的需求需要非同步演算法,您必須直接操作 Task 物件,而不是依賴編譯器支援。 另一個範例是建立迴圈。 通常,您會使用 forforeachwhiledo 迴圈來建立這些迴圈。 如您在本系列稍後所見,運算式樹狀架構的 API 支援單一迴圈運算式,並使用 breakcontinue 來控制重複迴圈。

您無法執行的作業是修改運算式樹狀架構。 運算式樹狀架構是不可變的資料結構。 如果您想要變動 (變更) 運算式樹狀架構,您必須複製原始樹狀並進行所需的變更,以建立新的樹狀。