Linq之Expression初見


目錄

寫在前面

系列文章

Expression

表達式樹創建方式

一個例子

總結

寫在前面

上篇文章介紹了擴展方法,這篇文章開始將陸續介紹在linq中使用最多的表達式樹的相關概念,以概念及例子一一列出如何在代碼中使用Expression。

系列文章

Linq之Lambda表達式初步認識

Linq之Lambda進階

Linq之隱式類型、自動屬性、初始化器、匿名類

Linq之擴展方法

Expression

還是老樣子,首先看MSDN中對表達式樹的描述

表達式樹以樹形數據結構表示代碼,其中每一個節點都是一種表達式,比如方法調用和 x < y 這樣的二元運算等。

你可以對表達式樹中的代碼進行編輯和運算。 這樣能夠動態修改可執行代碼、在不同數據庫中執行 LINQ 查詢以及創建動態查詢。 

表達式樹又稱為“表達式目錄樹”,以數據形式表示語言級代碼,它是一種抽象語法樹或者說是一種數據結構。

通過上面的描述,你會發現表達式樹的作用:動態修改可執行代碼、在不同數據庫中執行Linq查詢及創建動態查詢。那它是如何做到的呢?那下面就開始咱們的表達式樹之旅吧。

表達式樹創建方式

表達式樹創建方式分為兩種:以lambda表達式的方式創建,通過API靜態方法創建。

若 lambda 表達式被分配給 Expression<TDelegate> 類型的變量,則編譯器可以發射代碼以創建表示該 lambda 表達式的表達式樹。

看一個例子:

1   static void Main(string[] args)
2         {
3             System.Linq.Expressions.Expression<Func<int, bool>> lambda = num => num >= 5;
4         }

上面的代碼意思就以表達式目錄樹的形式將強類型的lambda表達式num=>num>=5標識為數據結構。

通過 API 創建表達式樹需要使用 Expression 類。

該類包含創建特定類型表達式樹節點的靜態工廠方法,比如表示參數變量的 ParameterExpression,或者是表示方法調用的 MethodCallExpression。 System.Linq.Expressions 名稱空間還解釋了 ParameterExpression、MethodCallExpression和另一種具體表達式類型。 這些類型來源於抽象類型 Expression。

那么我使用API的方式創建上面例子中的表達式樹:

說的很高大上,其實就是類Expression的一系列靜態方法。

首先引入命名空間

using System.Linq.Expressions;
 1         static void Main(string[] args)
 2         {
 3             //創建lambda表達式 num=>num>=5
 4             //第一步創建輸入參數,參數名為num,類型為int類型
 5             ParameterExpression numParameter = Expression.Parameter(typeof(int), "num");
 6             //第二步創建常量表達式5,類型int
 7             ConstantExpression constant = Expression.Constant(5, typeof(int));
 8             //第三步創建比較運算符>=,大於等於,並將輸入參數表達式和常量表達式輸入
 9             //表示包含二元運算符的表達式。BinaryExpression繼承自Expression
10             BinaryExpression greaterThanOrEqual = Expression.GreaterThanOrEqual(numParameter, constant);
11             //第四步構建lambda表達式樹
12             //Expression.Lambda<Func<int, bool>>:通過先構造一個委托類型來創建一個 LambdaExpression
13             Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(greaterThanOrEqual, numParameter);
14         }

 

通過上面的代碼你會發現這種方式在創建的時候,lambda表達式的左右及二元運算符都要分別的創建,然后在通過Expression.Lambda方法構建lambda表達式。

一個例子

在 .NET Framework 4 中,API 表達式樹還支持賦值表達式和控制流表達式,比如循環、條件塊和 try-catch 塊等。

看一個例子,通過API表達式樹創建一個利用循環求1到n的和的表達式樹。

如果能這樣寫該有多好啊

1             Expression<Func<int, int>> lambda = n =>
2             {
3                 int result = 0;
4                 for (int j = n; j >= 0; j--)
5                 {
6                     result += j;
7                 }
8                 return result;
9             };

可惜

通過API創建表達式樹,可以創建更為復雜的表達式樹,這里先嘗嘗鮮

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //變量表達式
 6             ParameterExpression i = Expression.Variable(typeof(int), "i");
 7             //變量表達式
 8             ParameterExpression sum = Expression.Variable(typeof(int), "sum");
 9             //跳出循環標志
10             LabelTarget label = Expression.Label(typeof(int));
11             //塊表達式
12             BlockExpression block =
13                 Expression.Block(
14                 //添加局部變量
15                     new[] { sum },
16                 //為sum賦初值 sum=1
17                 //Assign表示賦值運算符
18                     Expression.Assign(sum, Expression.Constant(1, typeof(int))),
19                 //loop循環
20                     Expression.Loop(
21                 //如果為true 然后求和,否則跳出循環
22                         Expression.IfThenElse(
23                 //如果i>=0
24                         Expression.GreaterThanOrEqual(i, Expression.Constant(0, typeof(int))),
25                 //sum=sum+i;i++;
26                                   Expression.AddAssign(sum, Expression.PostDecrementAssign(i)),
27                 //跳出循環
28                             Expression.Break(label, sum)
29                         ), label
30                      )  // Loop ends
31                  );
32             int resutl = Expression.Lambda<Func<int, int>>(block, i).Compile()(100);
33             Console.WriteLine(resutl);
34             Console.Read();
35         }
36     }

輸出結果

總結

本篇文章主要介紹了表達式樹的概念及兩種創建方式。在文章的結尾給出了一個例子,也是先嘗嘗鮮,對於代碼中的一些靜態方法可先參考注釋。下篇文章將介紹一些Expression的常用的靜態方法。

參考文章

http://msdn.microsoft.com/zh-cn/library/bb397951.aspx


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM