玩轉C#之【表達式目錄樹】

by NickChi
表達式目錄樹

環境安裝

這邊可以先安裝Expression Tree Visualizer工具

Viusla studio 2019 安裝方式:

檔案(ExpressionTreeVisualizer.2019)下載完之後,將檔案複製到此目錄:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Packages\Debugger

安裝教學

介紹

首先它來自Sysyem.Linq.Expressions命名空間,用以下的範例做個解說

static void Main(string[] args)
{
    Func<int, int, int> func1 = (m, n) => m * n + 2;
    Expression<Func<int, int, int>> exp = (m , n) => m * n + 2;

}

我們先觀察如果是一個委派VisualStudio會怎麼做解析,它會有一個Method跟Target
委派

在觀察如果是Expressions,其實就只是把代碼列出來的感覺一樣
表達式目錄

我們再透過上述提到的工具ExpressionTreeVisualizer觀察看看,它告訴了我們這個表達式樹是一個Func<int,int,int>類型的表達式樹,表達式目錄樹本質上是一個資料結構,資料結構中有幾個重要元素,其中包含這是屬於什麼類型的資料Lambda,並且body是它的核心,我們可以看出它也是一個表達式

解析過程1

可以從中看出它是一個簡單的二元表達式,從這個表達式中可以看出它的資料類型是Add,並且會有右邊和左邊的概念,右邊是一個常數,左邊是一個相乘的表達式

解析過程2

從圖中可以看出,左邊跟右邊的類型都是屬於參數表達式

解析過程3

從上述的解析過程我們可以發現,其實就是一個二元樹的資料結構
二元樹

表達式目錄樹=>是一種資料結構,可以被二元樹解析

:notes: 表達式目錄樹只能一行,無法帶入{ }

錯誤範例:

Expression<Func<int,int,int>> exp1 = (m,n) =>
{    
    return m*n+2
};

:notes:表達式目錄樹可以透過Compile方法,得到一個委派

int iResult1 = func.Invoke(12,23);
int iResult2 = exp.Compile().Invoke(12,23);

我們可以看一下,其實LINQ語法裡面傳遞的其實是表達式目錄樹,為什麼不能傳遞委派,因為委派的方法我們只能直接執行,沒辦法把它轉換成SQL語法的,我們在這裡傳遞得表達式目錄樹最終是要拆解成SQL語法。
Linq語法

動態拼裝表達式目錄樹和擴展應用

我們來反編譯一下,此程式

   Expression<Func<int, int, int>> exp = (m , n) => m * n + 2;

反編譯後會產生以下的程式
反編譯表達式目錄樹

並且我們在做下整理與比較
表達式目錄樹比較

從上述的比較可以看出 表達式目錄樹 有兩種宣告方式

範例解析:

範例解析

總結:

  • 可以用來替代反射,因為反射可以通用,但是性能不夠
  • 產生硬程式碼,可以提升性能

關於解析表達式目錄樹,生成SQL、表達式目錄樹拼裝連接之後會專門寫一篇文章跟大家講解

參考資料

Expression 類別

本篇已同步發表至個人部落格
https://moushih.com/2022ithome15/

鐵人賽文章

https://ithelp.ithome.com.tw/articles/10290798

You may also like

Leave a Comment