1. 程式人生 > >表示式樹練習實踐:入門基礎

表示式樹練習實踐:入門基礎

目錄

  • 表示式樹練習實踐:入門基礎
    • 什麼是表示式樹
    • 建立表示式樹
      • lambda 建立表示式樹
      • 通過 API 建立表示式樹
    • Expression< TDelegate >
    • 解析/執行表示式樹

表示式樹練習實踐:入門基礎

什麼是表示式樹

來自微軟官方文件的定義:

表示式樹以樹形資料結構表示程式碼。

它能幹什麼呢?

你可以對錶達式樹中的程式碼進行編輯和運算。 這樣能夠動態修改可執行程式碼、在不同資料庫中執行 LINQ 查詢以及建立動態查詢。

好不好玩?

表示式樹還能用於動態語言執行時 (DLR) 以提供動態語言和 .NET Framework 之間的互操作性,同時保證編譯器編寫員能夠發射表示式樹而非 Microsoft 中間語言 (MSIL)。

哪裡有應用?

ORM框架、工作流框架等,使用到 Lambda 的程式碼。。。動態執行程式碼、動態組裝程式碼等。

建立表示式樹

建立表示式樹有兩種方式:通過 lambda 表示式、通過 API。

建立表示式樹的意思是,在此之前已經編寫好每個結點,最後使用程式碼將所有結點組合起來,生成表示式樹。

示例(通過API建立表示式樹)

```
            ParameterExpression a = Expression.Parameter(typeof(int), "i");
            ParameterExpression b = Expression.Parameter(typeof(int), "j");

            Expression r1 = Expression.Multiply(a, b);      //乘法執行
            ParameterExpression c = Expression.Parameter(typeof(int), "x");
            ParameterExpression d = Expression.Parameter(typeof(int), "y");
            Expression r2 = Expression.Multiply(c, d);      //乘法執行

            Expression result = Expression.Add(r1, r2);     //相加
            //以上程式碼產生結點
            //生成表示式
            Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);
            var com = func.Compile();
            Console.WriteLine("表示式" + func);
            Console.WriteLine(com(12, 12, 13, 13));
            Console.ReadKey();

上面關於表示式樹的程式碼很多,以下這一步叫生成/建立表示式樹。

            Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);

以下這句叫執行表示式樹

            var com = func.Compile();

其它程式碼是用於生成表示式樹結點/邏輯。

迴歸正題,建立表示式樹的兩種方法。

lambda 建立表示式樹

上面的表示式樹示例,是用於生成

 ( i * j ) + ( x * y ) 

但是就這麼簡單的操作,要寫這麼長,實在不合理。

而通過 lambda ,可以這樣寫

           Expression<Func<int, int, int, int, int>> func = (i, j, x, y) => (i * j) + (x * y);

如果使用 lambda 生成表示式樹, lambda 只能使用單行語句,不能使用 if、for等語句。

具體關於 Lambda 的表示式樹,後面其它文章有說明。

通過 API 建立表示式樹

就是這樣

Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);

兩種方式左邊的都是一樣的,區別在於等號右邊。

Expression< TDelegate >

上面示例的最終結果都是生成

Expression<Func<int, int, int, int, int>> func 

func 是表示式樹變數。

我們可以瞭解以下表達式樹具有的方法和屬性。

用於生成表示式樹結點的,是 Expression 型別。

那麼,建立的表示式樹 func ,是 Expression<TDelegate>型別。

定義如下

public sealed class Expression<TDelegate> : LambdaExpression

具有方法如下

方法 說明
Compile() 將表示式樹描述的 lambda 表示式編譯為可執行程式碼,並生成表示 lambda 表示式的委託。
Compile(Boolean) 將表示式樹描述的 Lambda 表示式編譯為已解釋或已編譯的程式碼,並生成表示該 Lambda 表示式的委託。
Compile(DebugInfoGenerator) 將 lambda 編譯到方法定義中。 (Inherited from LambdaExpression)
Update(Expression, IEnumerable) 建立一個與此表示式類似的新表示式,但使用所提供的子級。 如果所有子級都相同,則將返回此表示式。
Accept(ExpressionVisitor) 排程到此節點型別的特定 Visit 方法。 例如,MethodCallExpression呼叫 VisitMethodCall。

由於 Expression<TDelegate> 繼承了 LambdaExpression,所以有很多屬性方法也可以用。

Body 獲取 lambda 表示式的主體。
CanReduce 指示可將節點簡化為更簡單的節點。 如果返回 true,則可以呼叫 Reduce() 以生成簡化形式。
Name 獲取 lambda 表示式的名稱。
NodeType 返回此 Expression 的節點型別。
Parameters 獲取 lambda 表示式的引數。
ReturnType 獲取 lambda 表示式的返回型別。
TailCall 獲取一個值,該值指示是否將通過尾呼叫優化來編譯 lambda 表示式。
Type 獲取此 Expression 表示的表示式的靜態型別。

好了,以上權當小筆記,備忘,目前先用不上,後面慢慢來使用。

解析/執行表示式樹

建立表示式樹後,就要執行表示式樹。

在此之前,你需要了解 委託 Delegate,Func,Action,以及他們中間的關係。

執行表示式樹是這樣子的

            Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);
            var com = func.Compile();
            var runRasult = com(12, 12, 13, 13);

func 只是一個表示式樹,我們把表示式樹構建好後,“要將表示式樹轉為程式碼”,使用

.Compile() 方法,可以將表示式樹生成一個 委託(例如上面的 com)。

為了簡潔上面使用了 var,實際上是這樣的

            Func<int,int,int,int,int> com = func.Compile();

四個引數,一個返回值。

var runRasult = com(12, 12, 13, 13);

C#裡有語法糖,對委託可以這樣寫

        Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);

        int runRasult = func.Compile()(12, 12, 13, 13);

以後後面都是這樣寫了,能夠縮成一行的程式碼,就沒必要寫出兩行。

在 Vs 裡面除錯和查看錶達式樹,可以看這裡

https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/expression-trees/debugging-expression-trees-in-visual-studio

初學者不必糾結於這些,瞭解一下本文內容,記一下概要資訊即