寫在前面
系列文章
變量表達式
常量表達式
條件表達式
賦值表達式
二元運算符表達式
一元運算符表達式
循環表達式
塊表達式
總結
首先回顧一下上篇文章的內容,上篇文章介紹了表達式樹的解析和編譯。如果忘記了,可以通過下面系列文章提供的入口進行復習。這篇文章將介紹常見的表達式類型。
常見的表達式類型都有個共同的基類Expression。創建這些類型的對象,是通過API的方式創建的(也就是Expression的靜態方法),首先引入命名空間:
1 using System.Linq.Expressions;
Linq之Lambda表達式初步認識
Linq之Lambda進階
Linq之隱式類型、自動屬性、初始化器、匿名類
Linq之擴展方法
Linq之Expression初見
Linq之Expression進階
在表達式樹中使用ParameterExpression或者ParameterExpression表達式表示變量類型,下面看一個例子,我們定義一個int類型的變量i:
// ParameterExpression表示命名的參數表達式。 ParameterExpression i = Expression.Parameter(typeof(int),"i");
或者使用
1 ParameterExpression j = Expression.Variable(typeof(int), "j");
通過f12轉到定義,發現這兩個方法的注釋幾乎是一樣的。靜態方法Parameter第一個參數:定義的參數類型,第二個參數:為參數名稱。
在表達式樹中使用ConstantExpression表達式表示具有常量值的表達式。,看一個例子,我們定義一個int類型的常量5.並將該值賦值給上面定義的變量i
1 // ParameterExpression表示命名的參數表達式。 2 ParameterExpression i = Expression.Parameter(typeof(int), "i"); 3 //ParameterExpression j = Expression.Variable(typeof(int), "j"); 4 ConstantExpression constExpr = Expression.Constant(5, typeof(int)); 5 // 創建一個表示賦值運算的 System.Linq.Expressions.BinaryExpression 6 //表示包含二元運算符的表達式。 7 BinaryExpression binaryExpression = Expression.Assign(i, constExpr);
Constrant方法第一個參數:常量,第二個參數為什麼類型的常量。
這裡提到了BinaryExpression表達式,該表達式標識包含二元運算符的表達式,類似與=,>這樣的二元表達式都可以使用BinaryExpression表達式來表示。
調試模式下,在自動窗口查看當前表達式的DebugView屬性,這個屬性在調試表達式樹的時候是非常有用的:
變量:
常量:
二元表達式:
通過觀察上面的圖,可知變量調試模式下DebugView屬性將顯示前面帶有“$”符號的 ParameterExpression 變量名稱。那麼如果參數沒有名稱,則會為其分配一個自動生成的名稱,例如 $var1 或 $var2(這裡不再舉例)。
在很多時候,我們都需要使用條件表達式來過濾一些數據,然後返回滿足條件的數據,在表達式中有這樣一些表達式滿足你的需求。
常見運算符
>,>=
<,<=
if....then:如果滿足條件那麼..
if...then...else:如果滿足條件執行某某代碼,否則執行另外的邏輯
一個例子
IfThenElse方法
1 public static ConditionalExpression IfThenElse( 2 Expression test, 3 Expression ifTrue, 4 Expression ifFalse 5 )
1 bool test = true; 2 ConditionalExpression codition = Expression.IfThenElse( 3 //條件 4 Expression.Constant(test), 5 //如果條件為true,調用WriteLine方法輸出“條件為true” 6 Expression.Call( 7 null, 8 typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), 9 Expression.Constant("條件為true") 10 ), 11 //如果條件false 12 Expression.Call( 13 null, 14 typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), 15 Expression.Constant("條件為false") 16 ) 17 ); 18 //編譯表達式樹,輸出結果 19 Expression.Lambda<Action>(codition).Compile()();
輸出結果
例子描述:條件test包裝為常量表達式,因為test為true,所以執行iftrue的表達式,並調用WriteLine方法打印出信息。
=
還以上面為變量i賦值的例子為例
1 ParameterExpression i = Expression.Parameter(typeof(int), "i"); 2 //ParameterExpression j = Expression.Variable(typeof(int), "j"); 3 ConstantExpression constExpr = Expression.Constant(5, typeof(int)); 4 // 創建一個表示賦值運算的 System.Linq.Expressions.BinaryExpression 5 //表示包含二元運算符的表達式。 6 BinaryExpression binaryExpression = Expression.Assign(i, constExpr);
+=
1 BinaryExpression b2 = Expression.AddAssign(i, constExpr);
-=
1 BinaryExpression b3 = Expression.SubtractAssign(i, constExpr);
*=
BinaryExpression b4 = Expression.MultiplyAssign(i, constExpr);
/=
1 BinaryExpression b5= Expression.DivideAssign(i, constExpr);
舉一個例子
1 ParameterExpression i = Expression.Parameter(typeof(int), "i"); 2 BlockExpression block = Expression.Block( 3 new[] { i }, 4 //賦初值 i=5 5 Expression.Assign(i, Expression.Constant(5, typeof(int))), 6 //i+=5 10 7 Expression.AddAssign(i, Expression.Constant(5, typeof(int))), 8 //i-=5 5 9 Expression.SubtractAssign(i, Expression.Constant(5, typeof(int))), 10 //i*=5 25 11 Expression.MultiplyAssign(i, Expression.Constant(5, typeof(int))), 12 //i/=5 5 13 Expression.DivideAssign(i, Expression.Constant(5, typeof(int))) 14 ); 15 Console.WriteLine(Expression.Lambda<Func<int>>(block).Compile()());
結果
在上面也提到了部分二元運算符表達式,類似加減乘除這樣的運算符,對於二元運算符,就不再舉例。這些返回的表達式樹,都可以使用BinaryExpression來接收,或者使用基類Expression接收,或者更省事,使用var關鍵字。
類似++,--運算符
i++等價於i=i+1,運算順序就是i先加1,然後再賦值給i。在表達式書中使用Expression的PostIncrementAssign方法來進行自增或者自減操作。返回結果為UnaryExpression類型,同樣可以使用基類Expression接收,或者var。
在表達式樹中使用Expression的Loop方法實現循環。
在前面的文章中,也說了不能使用Lambda方式創建帶塊級的表達式樹,不然會有如下的錯誤
通過API的方式可以創建塊級表達式樹,其中Expression的Block方法功不可沒。例如上面的加減乘除的例子中,可以包括多個Expression。
那麼,下面就舉一個包含自增的一元表達式,循環的表達式塊,並輸出結果。
輸出1-100之間的所有偶數。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //變量i 6 ParameterExpression i = Expression.Parameter(typeof(int), "i"); 7 //跳出循環 8 LabelTarget label = Expression.Label(); 9 BlockExpression block = Expression.Block( 10 new[] { i }, 11 //為i賦初值 12 Expression.Assign(i, Expression.Constant(1, typeof(int))), 13 Expression.Loop( 14 Expression.IfThenElse( 15 //如果i<=100 16 Expression.LessThanOrEqual(i, Expression.Constant(100, typeof(int))), 17 //如果為true.進入循環體 18 Expression.Block( 19 Expression.IfThen( 20 //條件i%2==0; 21 Expression.Equal(Expression.Modulo(i, Expression.Constant(2, typeof(int))), 22 Expression.Constant(0, typeof(int))), 23 Expression.Call(typeof(Console).GetMethod("WriteLine", 24 new Type[] { typeof(int) }), new[] { i })), 25 //i++ 26 Expression.PostIncrementAssign(i) 27 ), 28 //如果i>100 29 Expression.Break(label)), 30 label 31 )); 32 Expression.Lambda<Action>(block).Compile()(); 33 Console.Read(); 34 } 35 }
結果
本篇文章介紹了幾種常見的表達式類型,當然,還有很多並沒有列出,比如switch case,try catch等。如果在項目中需要創建復雜的表達式樹,Expression的靜態方法Block是必不可少的。希望通過本篇的學習,對你了解Expression有所幫助。
參考文章
https://msdn.microsoft.com/zh-cn/library/dd323961(v=vs.110).aspx
https://msdn.microsoft.com/zh-cn/library/bb397951.aspx