目錄
寫在前面
上篇文章介紹了擴展方法,這篇文章開始將陸續介紹在linq中使用最多的表達式樹的相關概念,以概念及例子一一列出如何在代碼中使用Expression。
系列文章
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