運算式樹狀架構

運算式樹狀架構代表類似樹狀架構的資料結構中程式碼,其中每個節點都是一個運算式,例如,方法呼叫或二進位作業 (例如 x < y)。

如果您使用過 LINQ,您會有豐富的程式庫使用經驗,其中 Func 類型是 API 集合的一部分 (如果您不熟悉 LINQ,您可能會想閱讀 LINQ 教學課程,並在此文章前參閱 Lambda 運算式一文。) 運算式樹狀架構提供更豐富的函式引數互動。

當您建立 LINQ 查詢時,通常會使用 Lambda 運算式來撰寫函式引數。 在一般 LINQ 查詢中,這些函式引數會轉換成編譯器所建立的委派。

您可能已撰寫使用運算式樹狀架構的程式碼。 Entity Framework 的 LINQ API 接受運算式樹狀架構作為 LINQ 查詢運算式模式的引數。 這可讓 Entity Framework 將以 C# 撰寫的查詢,轉譯為在資料庫引擎中執行的 SQL。 另一個範例是 Moq,這是 .NET 的熱門模擬架構。

當您想要有更豐富的互動時,您必須使用「運算式樹狀架構」。 運算式樹狀架構會以您查看、修改或執行的結構來表示程式碼。 這些工具可讓您在執行階段操作程式碼。 您可撰寫程式碼來查看執行中的演算法,或插入新功能。 在更進階的案例中,您會修改執行中的演算法,甚至將 C# 運算式轉譯為其他格式,以便在其他環境中執行。

您可編譯和執行運算式樹狀架構所表示的程式碼。 建置並執行運算式樹狀架構,會啟用可執行程式碼的動態修改作業、在各種資料庫中執行 LINQ 查詢,以及建立動態查詢。 如需 LINQ 中運算式樹狀架構的詳細資訊,請參閱如何使用運算式樹狀架構建置動態查詢

運算式樹狀架構也用於動態語言執行階段 (DLR) 中,以提供動態語言與 .NET 之間的互通性,並讓編譯器寫入器發出運算式樹狀架構,而不是 Microsoft Intermediate Language (MSIL)。 如需 DLR 的詳細資訊,請參閱 Dynamic Language Runtime 概觀

您可以根據匿名 Lambda 運算式讓 C# 或 Visual Basic 編譯器建立運算式樹狀架構,也可以使用 System.Linq.Expressions 命名空間以手動建立運算式樹狀架構。

將 Lambda 運算式指派給類型為 Expression<TDelegate> 的變數時,編譯器會發出程式碼,以建置代表 Lambda 運算式的運算式樹狀架構。

C# 編譯器只會從運算式 Lambda (或單行 Lambda) 產生運算式樹狀架構。 其無法剖析陳述式 Lambda (或多行 Lambda)。 如需 C# 中之 Lambda 運算式的詳細資訊,請參閱 Lambda 運算式

下列程式碼範例示範如何讓 C# 編譯器建立代表 Lambda 運算式 num => num < 5 的運算式樹狀架構。

Expression<Func<int, bool>> lambda = num => num < 5;

您可在程式碼中建立運算式樹狀架構。 若要建置樹狀架構,您可以建立每個節點,並將節點連結至樹狀架構。 如需了解如何建立運算式,請參閱建置運算式樹狀架構一文。

運算式樹狀結構不可變。 若要修改運算式樹狀架構,您必須複製現有運算式樹狀架構並取代其中節點,藉此建構新的運算式樹狀架構。 您可以使用運算式樹狀架構造訪者來周遊現有運算式樹狀架構。 如需詳細資訊,請參閱轉譯運算式樹狀架構一文。

建置運算式樹狀結構之後,您可以執行運算式樹狀架構所表示的程式碼

限制

某些較新的 C# 語言項目無法正確轉譯為運算式樹狀架構。 運算式樹狀架構不能含有 await 運算式或 async Lambda 運算式。 C# 6 和更新版本中新增的許多功能,似乎與寫入運算式樹狀架構的功能不同。 相反地,較新的功能會以舊版的對等語法公開在運算式樹狀架構中 (若適用)。 無法使用其他建構。 這表示當引進新的語言功能時,解譯運算式樹狀架構的程式碼會以相同方式運作。 不過,即使有這些限制,運算式樹狀架構還是可讓您建立與解譯和修改程式碼 (以資料結構表示) 有關的動態演算法。 其可讓 Entity Framework 等豐富的程式庫完成作業。

運算式樹狀架構不支援新的運算式節點型別。 對於所有解譯運算式樹狀架構的程式庫而言,引進新的節點型別是一項重大變更。 下列清單包含大部分無法使用的 C# 語言元素: