欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
LINQ與DLR的Expression tree(4):創(chuàng )建靜態(tài)類(lèi)型的LINQ表達式樹(shù)節點(diǎn) (轉 rednaxelafx.javaeye.com)

LINQ與DLR的Expression tree(4):創(chuàng )建靜態(tài)類(lèi)型的LINQ表達式樹(shù)節點(diǎn)

關(guān)鍵字: linq dlr expression tree
(Disclaimer:如果需要轉載請先與我聯(lián)系;文中圖片請不要直接鏈接
作者:RednaxelaFX at rednaxelafx.javaeye.com)

系列文章:
LINQ與DLR的Expression tree(1):簡(jiǎn)介L(cháng)INQ與Expression tree
LINQ與DLR的Expression tree(2):簡(jiǎn)介DLR
LINQ與DLR的Expression tree(3):LINQ與DLR的樹(shù)的對比
LINQ與DLR的Expression tree(4):創(chuàng )建靜態(tài)類(lèi)型的LINQ表達式樹(shù)節點(diǎn)
LINQ與DLR的Expression tree(5):用lambda表達式表示常見(jiàn)控制結構

系列的前三篇介紹過(guò)LINQ與DLR中的expressiontree的概況后,我們對LINQ與DLR所使用的AST的概況和關(guān)系應該有一定認識了。既然LINQ Expression tree現在是DLRtree的子集,而DLR能夠使用DLR tree來(lái)支持動(dòng)態(tài)類(lèi)型的語(yǔ)言,那么LINQ Expressiontree能不能同樣支持動(dòng)態(tài)類(lèi)型方式的呢?系列接下來(lái)的文章就會(huì )圍繞這個(gè)主題,描繪一個(gè)從使用LINQ Expressiontree過(guò)渡到使用DLR tree的過(guò)程。

本篇,我們先來(lái)詳細看看要自己手工創(chuàng )建一棵LINQ Expression tree大概是個(gè)什么樣子。

System.Linq.Expressions.Expression類(lèi)上的工廠(chǎng)方法

在第一篇介紹LINQ Expressiontree的時(shí)候提到過(guò),創(chuàng )建節點(diǎn)主要是通過(guò)調用Expression類(lèi)上的靜態(tài)工廠(chǎng)方法,而不是直接使用具體的Expression類(lèi)的構造器來(lái)完成的。下面直接用代碼來(lái)演示C#中的一些基本表達式結構是如何用Expressiontree來(lái)表示的,并在代碼最后的Main()方法里演示一個(gè)稍微復雜一點(diǎn)的表達式的構造。

由于代碼比較長(cháng),下面將分段把代碼貼出來(lái)。如果用IE瀏覽提示“腳本可能失去響應”,請不要擔心,并選擇繼續執行腳本。本文的完整代碼可以通過(guò)附件下載。

常量表達式部分
沒(méi)什么值得解釋的,就是通過(guò)Expression.Constant()來(lái)表示一個(gè)常量。注意一個(gè)常量可以是C#里的字面量,如0、1、2.0、"abc"、null等,也可以是任意別的語(yǔ)義上符合“常量”概念的對象。
C#代碼
  1. // By RednaxelaFX, 2008-09-07  
  2.   
  3. using System;  
  4. using System.Collections.Generic;  
  5. using System.Linq.Expressions;  
  6.   
  7. static class ExpressionTreeSamples {  
  8.  
  9.     #region Constant  
  10.   
  11.     // Represents a constant (such as a literal)  
  12.     static void Constant( ) {  
  13.         // Expression<Func<int>> con = ( ) => 1;  
  14.         Expression<Func<int>> con = Expression.Lambda<Func<int>>(  
  15.             Expression.Constant(  
  16.                 1,            // value  
  17.                 typeofint ) // type  
  18.             ),  
  19.             new ParameterExpression[ ] { }  
  20.         );  
  21.     }  
  22.  
  23.     #endregion  


算術(shù)表達式部分
這部分代碼演示了+、-、*、/、%、冪、一元-、一元+等運算符在Expression tree中的對應物。需要說(shuō)明的地方有五點(diǎn):

1、.NET中算術(shù)運算可以?huà)伋鯫verflowException來(lái)表示運算結果溢出(overflow)了,也就是超過(guò)了數據類(lèi)型所能表示的范圍。用戶(hù)可以選擇不理會(huì )這些異常(unchecked)或者關(guān)注這些異常(checked)。C#中默認是unchecked??梢詫σ粋€(gè)表達式或者一個(gè)語(yǔ)句塊指定checked與unchecked。與此相應,Expression tree API中也對算術(shù)運算(和類(lèi)型轉換運算)提供了checked與unchecked的兩個(gè)版本。

2、在第二個(gè)Add()的例子里,原本的lambda表達式只接受一個(gè)參數(y),但在表達式內容中使用了一個(gè)自由變量(x)。這個(gè)時(shí)候如果是由C#編譯器來(lái)編譯,就會(huì )自動(dòng)生成一個(gè)私有內部類(lèi)(這里用CompilerGeneratedDisplayClass來(lái)模擬),并將自由變量x變?yōu)槠涑蓡T變量。主要是想通過(guò)這個(gè)例子來(lái)演示自己如何通過(guò)創(chuàng )建類(lèi)似的類(lèi)來(lái)模擬lambda表達式對自由變量的捕獲(也就是閉包的功能)。

3、Divide()與DivideDouble()實(shí)際上演示的都是Expression.Divide()的使用。特意用兩個(gè)例子來(lái)演示是為了說(shuō)明無(wú)論是整型除法還是浮點(diǎn)數除法,Expression.Divide()都能正確處理。Expressiontree中的其它算術(shù)表達式也是同理。

4、C#中沒(méi)有冪運算符,所以Power()中的lambda表達式是用VB.NET來(lái)寫(xiě)的;VB.NET有冪運算符,“^”,不過(guò)實(shí)際上也是映射到Math.Pow()上的調用而已。

5、UnaryPlus()中演示的lambda表達式實(shí)際被C#編譯器編譯時(shí)是不會(huì )生成對Expression.UnaryPlus()的調用的,因為這個(gè)運算符作用在int上并沒(méi)有什么意義,只是直接返回其操作數的值而已。但是Expression treeAPI允許用戶(hù)指定在創(chuàng )建這些算術(shù)運算表達式節點(diǎn)時(shí)使用什么方法來(lái)執行運算,當用戶(hù)選擇使用默認以外的方法時(shí),這個(gè)表達式還是可能有不同的意義的。例如這個(gè)Expression.UnaryPlus有兩個(gè)版本的重載:
默認方法:
C#代碼
  1. public static UnaryExpression UnaryPlus( Expression expression )  

用戶(hù)指定方法:
C#代碼
  1. public static UnaryExpression UnaryPlus( Expression expression, MethodInfo method )  

采用第二個(gè)版本時(shí),根據以下規則判斷使用什么方法來(lái)實(shí)現一元加:
引用
  • 如果 method 不為 null 引用(在 Visual Basic 中為 Nothing),并且它表示帶一個(gè)參數的非 void static(在 Visual Basic 中為 Shared)方法,則它是節點(diǎn)的實(shí)現方法。
  • 如果 expression.Type 為定義一元正運算符的用戶(hù)定義的類(lèi)型,則表示此運算符的 MethodInfo 為實(shí)現方法。
  • 否則,如果 expression.Type 為數值類(lèi)型,則實(shí)現方法為 null 引用(在 Visual Basic 中為 Nothing)。
C#代碼
  1. #region Arithmetic  
  2.   
  3. // "+" operator  
  4. static void Add( ) {  
  5.     // Expression<Func<int, int, int>> add = ( x, y ) => x + y;  
  6.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  7.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  8.     Expression<Func<intintint>> add = Expression.Lambda<Func<intintint>>(  
  9.         Expression.Add(  
  10.             x, // left  
  11.             y  // right  
  12.         ),  
  13.         new ParameterExpression[ ] { x, y }  
  14.     );  
  15. }  
  16.   
  17. // simulates a compiler generated closure class  
  18. private class CompilerGeneratedDisplayClass {  
  19.     public int x;  
  20. }  
  21.   
  22. static void Add( int x ) {  
  23.     // Expression<Func<int, int>> add = y => x + y;  
  24.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  25.     var display = new CompilerGeneratedDisplayClass( );  
  26.     display.x = x;  
  27.     Expression<Func<intint>> add = Expression.Lambda<Func<intint>>(  
  28.         Expression.Add(  
  29.             Expression.Field(  
  30.                 Expression.Constant( display ),  
  31.                 typeof( CompilerGeneratedDisplayClass ).GetField( "x" )  
  32.             ),  
  33.             y  
  34.         ),  
  35.         new ParameterExpression[ ] { y }  
  36.     );  
  37. }  
  38.   
  39. // "+" operator, checked  
  40. static void AddChecked( ) {  
  41.     // Expression<Func<int, int, int>> add = ( x, y ) => checked( x + y );  
  42.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  43.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  44.     Expression<Func<intintint>> add = Expression.Lambda<Func<intintint>>(  
  45.         Expression.AddChecked(  
  46.             x, // left  
  47.             y  // right  
  48.         ),  
  49.         new ParameterExpression[ ] { x, y }  
  50.     );  
  51. }  
  52.   
  53. // "-" operator  
  54. static void Subtract( ) {  
  55.     // Expression<Func<int, int, int>> sub = ( x, y ) => x - y;  
  56.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  57.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  58.     Expression<Func<intintint>> sub = Expression.Lambda<Func<intintint>>(  
  59.         Expression.Subtract(  
  60.             x, // left  
  61.             y  // right  
  62.         ),  
  63.         new ParameterExpression[ ] { x, y }  
  64.     );  
  65. }  
  66.   
  67. // "-" operator, checked  
  68. static void SubtractChecked( ) {  
  69.     // Expression<Func<int, int, int>> sub = ( x, y ) => checked( x - y );  
  70.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  71.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  72.     Expression<Func<intintint>> sub = Expression.Lambda<Func<intintint>>(  
  73.         Expression.SubtractChecked(  
  74.             x, // left  
  75.             y  // right  
  76.         ),  
  77.         new ParameterExpression[ ] { x, y }  
  78.     );  
  79. }  
  80.   
  81. // "*" operator  
  82. static void Multiply( ) {  
  83.     // Expression<Func<int, int, int>> mul = ( x, y ) => x * y;  
  84.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  85.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  86.     Expression<Func<intintint>> mul = Expression.Lambda<Func<intintint>>(  
  87.         Expression.Multiply(  
  88.             x, // left  
  89.             y  // right  
  90.         ),  
  91.         new ParameterExpression[ ] { x, y }  
  92.     );  
  93. }  
  94.   
  95. // "*" operator, checked  
  96. static void MultiplyChecked( ) {  
  97.     // Expression<Func<int, int, int>> mul = ( x, y ) => checked( x * y );  
  98.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  99.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  100.     Expression<Func<intintint>> mul = Expression.Lambda<Func<intintint>>(  
  101.         Expression.MultiplyChecked(  
  102.             x, // left  
  103.             y  // right  
  104.         ),  
  105.         new ParameterExpression[ ] { x, y }  
  106.     );  
  107. }  
  108.   
  109. // "/" operator (demonstrates integral division)  
  110. static void Divide( ) {  
  111.     // Expression<Func<int, int, int>> div = ( x, y ) => x / y;  
  112.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  113.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  114.     Expression<Func<intintint>> div = Expression.Lambda<Func<intintint>>(  
  115.         Expression.Divide(  
  116.             x, // left  
  117.             y  // right  
  118.         ),  
  119.         new ParameterExpression[ ] { x, y }  
  120.     );  
  121. }  
  122.   
  123. // // "+" operator (demonstrates floating-point division)  
  124. static void DivideDouble( ) {  
  125.     // Note that this expression tree has exactly the same shape as the one  
  126.     // in Divide(). The only difference is the type of parameters and result.  
  127.     // The expression tree can find correct implementation of the divide operator  
  128.     // in both cases.  
  129.   
  130.     // Expression<Func<double, double, double>> div = ( x, y ) => x / y;  
  131.     ParameterExpression x = Expression.Parameter( typeofdouble ), "x" );  
  132.     ParameterExpression y = Expression.Parameter( typeofdouble ), "y" );  
  133.     Expression<Func<doubledoubledouble>> div = Expression.Lambda<Func<doubledoubledouble>>(  
  134.         Expression.Divide(  
  135.             x, // left  
  136.             y  // right  
  137.         ),  
  138.         new ParameterExpression[ ] { x, y }  
  139.     );  
  140. }  
  141.   
  142. // "%" operator  
  143. static void Modulo( ) {  
  144.     // Expression<Func<int, int, int>> mod = ( x, y ) => x % y;  
  145.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  146.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  147.     Expression<Func<intintint>> mod = Expression.Lambda<Func<intintint>>(  
  148.         Expression.Modulo(  
  149.             x, // left  
  150.             y  // right  
  151.         ),  
  152.         new ParameterExpression[ ] { x, y }  
  153.     );  
  154. }  
  155.   
  156. // exponentiation operator (not available in C#)  
  157. static void Power( ) {  
  158.     // There‘s no "raise to the power" operator in C#, but there is one  
  159.     // in VB.NET, the "^" operator.  
  160.     // So this sample is in VB9:  
  161.     // Dim pow As Expression(Of Func(Of Integer, Integer, Integer)) _  
  162.     //     = Function( x, y ) x ^ y  
  163.   
  164.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  165.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  166.     Expression<Func<intintint>> pow = Expression.Lambda<Func<intintint>>(  
  167.         Expression.Power(  
  168.             x, // left  
  169.             y  // right  
  170.         ),  
  171.         new ParameterExpression[ ] { x, y }  
  172.     );  
  173. }  
  174.   
  175. // unary "-" operator  
  176. static void Negate( ) {  
  177.     // Expression<Func<int, int>> neg = x => -x;  
  178.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  179.     Expression<Func<intint>> neg = Expression.Lambda<Func<intint>>(  
  180.         Expression.Negate(  
  181.             x // expression  
  182.         ),  
  183.         new ParameterExpression[ ] { x }  
  184.     );  
  185. }  
  186.   
  187. // unary "-" operator, checked  
  188. static void NegateChecked( ) {  
  189.     // Expression<Func<int, int>> neg = x => checked( -x );  
  190.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  191.     Expression<Func<intint>> neg = Expression.Lambda<Func<intint>>(  
  192.         Expression.NegateChecked(  
  193.             x // expression  
  194.         ),  
  195.         new ParameterExpression[ ] { x }  
  196.     );  
  197. }  
  198.   
  199. // unary "+" operator  
  200. static void UnaryPlus( ) {  
  201.     // Note that C# compiler will optimize this by removing the unary plus  
  202.     //Expression<Func<int, int>> unary = x => +x;  
  203.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  204.     Expression<Func<intint>> unaryPlus = Expression.Lambda<Func<intint>>(  
  205.         Expression.UnaryPlus(  
  206.             x // expression  
  207.         ),  
  208.         new ParameterExpression[ ] { x }  
  209.     );  
  210. }  
  211.  
  212. #endregion  


按位運算表達式部分
有兩點(diǎn)需要說(shuō)明:

1、C#中(以及.NET Framework的基礎類(lèi)庫(BCL)中沒(méi)有邏輯右移運算符“>>>”,而Java、JavaScript等語(yǔ)言中是存在這個(gè)運算符的。

2、千萬(wàn)要注意,Expression.And()Expression.Or()是表示按位運算用的,而Expression.AndAlso()Expression.OrElse()才是表示邏輯運算的。
C#代碼
  1. #region Bitwise  
  2.   
  3. // "<<" operator  
  4. static void LeftShift( ) {  
  5.     // Expression<Func<int, int, int>> lshift = ( x, y ) => x << y;  
  6.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  7.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  8.     Expression<Func<intintint>> lshift = Expression.Lambda<Func<intintint>>(  
  9.         Expression.LeftShift(  
  10.             x, // left  
  11.             y  // right  
  12.         ),  
  13.         new ParameterExpression[ ] { x, y }  
  14.     );  
  15. }  
  16.   
  17. // ">>" operator  
  18. static void RightShift( ) {  
  19.     // Expression<Func<int, int, int>> rshift = ( x, y ) => x >> y;  
  20.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  21.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  22.     Expression<Func<intintint>> expression = Expression.Lambda<Func<intintint>>(  
  23.         Expression.RightShift(  
  24.             x, // left  
  25.             y  // right  
  26.         ),  
  27.         new ParameterExpression[ ] { x, y }  
  28.     );  
  29.   
  30.     // Note that C# doesn‘t have a logical right shift operator ">>>",  
  31.     // neither is there one in the expression tree  
  32. }  
  33.   
  34. // "&" operator  
  35. static void And( ) {  
  36.     // Note that And() is for bitwise and, and AndAlso() is for logical and.  
  37.   
  38.     // Expression<Func<int, int, int>> and = ( x, y ) => x & y;  
  39.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  40.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  41.     Expression<Func<intintint>> and = Expression.Lambda<Func<intintint>>(  
  42.         Expression.And(  
  43.             x, // left  
  44.             y  // right  
  45.         ),  
  46.         new ParameterExpression[ ] { x, y }  
  47.     );  
  48. }  
  49.   
  50. // "|" operator  
  51. static void Or( ) {  
  52.     // Note that Or() is for bitwise or, and OrElse() is for logical or.  
  53.   
  54.     // Expression<Func<int, int, int>> or = ( x, y ) => x | y;  
  55.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  56.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  57.     Expression<Func<intintint>> or = Expression.Lambda<Func<intintint>>(  
  58.         Expression.Or(  
  59.             x,  
  60.             y  
  61.         ),  
  62.         new ParameterExpression[ ] { x, y }  
  63.     );  
  64. }  
  65.   
  66. // "^" operator  
  67. static void ExclusiveOr( ) {  
  68.     // Expression<Func<int, int, int>> xor = ( x, y ) => x ^ y;  
  69.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  70.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  71.     Expression<Func<intintint>> xor = Expression.Lambda<Func<intintint>>(  
  72.         Expression.ExclusiveOr(  
  73.             x, // left  
  74.             y  // right  
  75.         ),  
  76.         new ParameterExpression[ ] { x, y }  
  77.     );  
  78. }  
  79.  
  80. #endregion  


條件表達式部分
也就是C-like語(yǔ)言中常見(jiàn)的三元運算符“? :”。注意這個(gè)對應的不是if-else語(yǔ)句,而是條件表達式——C-like語(yǔ)言中表達式有值,語(yǔ)句不一定有(即便有值也被忽略了);條件表達式的兩個(gè)分支的值的類(lèi)型必須匹配。
C#代碼
  1. #region Conditional  
  2.   
  3. // "? :" operator  
  4. static void Condition( ) {  
  5.     // Expression<Func<bool, int, int, int>> cond = ( c, x, y ) => c ? x : y;  
  6.     ParameterExpression c = Expression.Parameter( typeofbool ), "c" );  
  7.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  8.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  9.     Expression<Func<boolintintint>> cond = Expression.Lambda<Func<boolintintint>>(  
  10.         Expression.Condition(  
  11.             c, // test  
  12.             x, // if true  
  13.             y  // if false  
  14.         ),  
  15.         new ParameterExpression[ ] { c, x, y }  
  16.     );  
  17. }  
  18.  
  19. #endregion  


相等性表達式部分
也就是等于大于小于等比較大小的部分。比較直觀(guān),不多說(shuō)。
C#代碼
  1. #region Equality  
  2.   
  3. // "==" operator  
  4. static void Equal( ) {  
  5.     // Expression<Func<int, int, bool>> eq = ( x, y ) => x == y;  
  6.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  7.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  8.     Expression<Func<intintbool>> eq = Expression.Lambda<Func<intintbool>>(  
  9.         Expression.Equal(  
  10.             x, // left  
  11.             y  // right  
  12.         ),  
  13.         new ParameterExpression[ ] { x, y }  
  14.     );  
  15. }  
  16.   
  17. // "!=" operator  
  18. static void NotEqual( ) {  
  19.     // Expression<Func<int, int, bool>> neq = ( x, y ) => x != y;  
  20.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  21.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  22.     Expression<Func<intintbool>> neq = Expression.Lambda<Func<intintbool>>(  
  23.         Expression.NotEqual(  
  24.             x, // left  
  25.             y  // right  
  26.         ),  
  27.         new ParameterExpression[ ] { x, y }  
  28.     );  
  29.   
  30.     // Note that the lambda above isn‘t equivalent to the following:  
  31.     // Expression<Func<int, int, bool>> neq2 = ( x, y ) => !( x == y );  
  32. }  
  33.   
  34. // ">" operator  
  35. static void GreaterThan( ) {  
  36.     // Expression<Func<int, int, bool>> gt = ( x, y ) => x > y;  
  37.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  38.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  39.     Expression<Func<intintbool>> gt = Expression.Lambda<Func<intintbool>>(  
  40.         Expression.GreaterThan(  
  41.             x, // left  
  42.             y  // right  
  43.         ),  
  44.         new ParameterExpression[ ] { x, y }  
  45.     );  
  46. }  
  47.   
  48. // ">=" operator  
  49. static void GreaterThanOrEqual( ) {  
  50.     // Expression<Func<int, int, bool>> ge = ( x, y ) => x >= y;  
  51.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  52.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  53.     Expression<Func<intintbool>> ge = Expression.Lambda<Func<intintbool>>(  
  54.         Expression.GreaterThanOrEqual(  
  55.             x, // left  
  56.             y  // right  
  57.         ),  
  58.         new ParameterExpression[ ] { x, y }  
  59.     );  
  60. }  
  61.   
  62. // "<" operator  
  63. static void LessThan( ) {  
  64.     // Expression<Func<int, int, bool>> lt = ( x, y ) => x < y;  
  65.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  66.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  67.     Expression<Func<intintbool>> lt = Expression.Lambda<Func<intintbool>>(  
  68.         Expression.LessThan(  
  69.             x, // left  
  70.             y  // right  
  71.         ),  
  72.         new ParameterExpression[ ] { x, y }  
  73.     );  
  74. }  
  75.   
  76. // "<=" operator  
  77. static void LessThanOrEqual( ) {  
  78.     // Expression<Func<int, int, bool>> le = ( x, y ) => x <= y;  
  79.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  80.     ParameterExpression y = Expression.Parameter( typeofint ), "y" );  
  81.     Expression<Func<intintbool>> le = Expression.Lambda<Func<intintbool>>(  
  82.         Expression.LessThanOrEqual(  
  83.             x, // left  
  84.             y  // right  
  85.         ),  
  86.         new ParameterExpression[ ] { x, y }  
  87.     );  
  88. }  
  89.  
  90. #endregion  


關(guān)系表達式部分
基本上只要注意好與前面按位運算的And()、Or()區分開(kāi)就行。另外需要記住的是,Expression.AndAlso()與Expression.OrElse()的默認語(yǔ)義與C#/C++中的&&、||一樣,是短路表達式——會(huì )根據對左操作數求值的結果決定是否對右操作數求值。
C#代碼
  1. #region Relational  
  2.   
  3. // "&&" operator  
  4. static void AndAlso( ) {  
  5.     // Note that And() is for bitwise and, and AndAlso() is for logical and.  
  6.     // Note also that the shortcut semantics is implemented with AndAlso().  
  7.   
  8.     // Expression<Func<bool, bool, bool>> and = ( x, y ) => x && y;  
  9.     ParameterExpression x = Expression.Parameter( typeofbool ), "x" );  
  10.     ParameterExpression y = Expression.Parameter( typeofbool ), "y" );  
  11.     Expression<Func<boolboolbool>> and = Expression.Lambda<Func<boolboolbool>>(  
  12.         Expression.AndAlso(  
  13.             x, // left  
  14.             y  // right  
  15.         ),  
  16.         new ParameterExpression[ ] { x, y }  
  17.     );  
  18. }  
  19.   
  20. // "||" operator  
  21. static void OrElse( ) {  
  22.     // Note that Or() is for bitwise or, and OrElse() is for logical or.  
  23.     // Note also that the shortcut semantics is implemented with OrElse().  
  24.   
  25.     // Expression<Func<bool, bool, bool>> or = ( x, y ) => x || y;  
  26.     ParameterExpression x = Expression.Parameter( typeofbool ), "x" );  
  27.     ParameterExpression y = Expression.Parameter( typeofbool ), "y" );  
  28.     Expression<Func<boolboolbool>> or = Expression.Lambda<Func<boolboolbool>>(  
  29.         Expression.OrElse(  
  30.             x, // left  
  31.             y  // right  
  32.         ),  
  33.         new ParameterExpression[ ] { x, y }  
  34.     );  
  35. }  
  36.   
  37. // "!" operator  
  38. static void Not( ) {  
  39.     // Expression<Func<bool, bool>> or = b => !b;  
  40.     ParameterExpression b = Expression.Parameter( typeofbool ), "b" );  
  41.     Expression<Func<boolbool>> not = Expression.Lambda<Func<boolbool>>(  
  42.         Expression.Not(  
  43.             b // expression  
  44.         ),  
  45.         new ParameterExpression[ ] { b }  
  46.     );  
  47. }  
  48.  
  49. #endregion  


類(lèi)型轉換表達式部分
注意點(diǎn)就在于.NET中的值類(lèi)型(value type)只能用C-style的類(lèi)型轉換,所以也只能對應Expression.Convert();而引用類(lèi)型(reference type)既可以用C-style的也可以用as運算符來(lái)做類(lèi)型轉換,可以根據需要選用Expression.Convert()或者Expression.TypeAs()。

對了,對C#不熟悉的人可能對??運算符感到陌生。這個(gè)運算符的語(yǔ)義是:當左操作數不為null時(shí),該表達式的值為左操作數的值;反之則為右操作數的值。
C#代碼
  1. #region Type Conversion  
  2.   
  3. // C-style conversion  
  4. static void Convert( ) {  
  5.     // Expression<Func<int, short>> conv = x => ( short ) x;  
  6.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  7.     Expression<Func<intshort>> conv = Expression.Lambda<Func<intshort>>(  
  8.         Expression.Convert(  
  9.             x,              // expression  
  10.             typeofshort ) // type  
  11.         ),  
  12.         new ParameterExpression[ ] { x }  
  13.     );  
  14. }  
  15.   
  16. // C-style conversion, checked  
  17. static void ConvertChecked( ) {  
  18.     // Expression<Func<int, short>> conv = x => checked( ( short ) x );  
  19.     ParameterExpression x = Expression.Parameter( typeofint ), "x" );  
  20.     Expression<Func<intshort>> conv = Expression.Lambda<Func<intshort>>(  
  21.         Expression.ConvertChecked(  
  22.             x,              // expression  
  23.             typeofshort ) // type  
  24.         ),  
  25.         new ParameterExpression[ ] { x }  
  26.     );  
  27. }  
  28.   
  29. // "as" operator  
  30. static void TypeAs( ) {  
  31.     // Expression<Func<string, object>> typeAs = x => x as object;  
  32.     ParameterExpression x = Expression.Parameter( typeofstring ), "x" );  
  33.     Expression<Func<stringobject>> typeAs = Expression.Lambda<Func<stringobject>>(  
  34.         Expression.TypeAs(  
  35.             x,               // expression  
  36.             typeofobject ) // type  
  37.         ),  
  38.         new ParameterExpression[ ] { x }  
  39.     );  
  40. }  
  41.   
  42. // "is" operator  
  43. static void TypeIs( ) {  
  44.     // Expression<Func<string, bool>> typeIs = x => x is object;  
  45.     ParameterExpression x = Expression.Parameter( typeofstring ), "x" );  
  46.     Expression<Func<stringbool>> typeIs = Expression.Lambda<Func<stringbool>>(  
  47.         Expression.TypeIs(  
  48.             x,               // expression  
  49.             typeofobject ) // type  
  50.         ),  
  51.         new ParameterExpression[ ] { x }  
  52.     );  
  53. }  
  54.   
  55. // "??" operator  
  56. static void Coalesce( ) {  
  57.     // Expression<Func<int?, int>> coal = x => x ?? 1;  
  58.     ParameterExpression x = Expression.Parameter( typeofint? ), "x" );  
  59.     Expression<Func<int?, int>> coal = Expression.Lambda<Func<int?, int>>(  
  60.         Expression.Coalesce(  
  61.             x,                                      // left  
  62.             Expression.Constant( 1, typeofint ) ) // right  
  63.         ),  
  64.         new ParameterExpression[ ] { x }  
  65.     );  
  66. }  
  67.  
  68. #endregion  


成員表達式部分
這里的“成員”主要是指域(field)和屬性(property)了。
在演示Expression.Field()的時(shí)候我用了前面模擬編譯器生成的內部類(lèi),只是圖個(gè)方便而已,因為實(shí)在想不到.NET基礎類(lèi)庫里(特別是System命名空間里)有什么類(lèi)型會(huì )包含共有域并且該域不是常量的。Int32.MaxValue是一個(gè)公有域,但同時(shí)也是個(gè)常量,C#編譯器一編譯就把lambda表達式里的域訪(fǎng)問(wèn)優(yōu)化成一個(gè)常量了。所以干脆用一個(gè)自定義的類(lèi)來(lái)演示域訪(fǎng)問(wèn)表達式。
Expression treeAPI里除了Expression.Field()和Expression.Property(),還有一個(gè)Expression.PropertyOrField()工廠(chǎng)方法。但我沒(méi)想出來(lái)在什么情況下無(wú)法得知一個(gè)名字到底是成員域還是成員屬性,所以沒(méi)寫(xiě)這個(gè)對應的例子。
C#代碼
  1. #region Member  
  2.   
  3. // Accessing a field  
  4. static void Field( ) {  
  5.     // Reusing the CompilerGeneratedDisplayClass class for demo.  
  6.   
  7.     //Expression<Func<CompilerGeneratedDisplayClass, int>> field = c => c.x;  
  8.     ParameterExpression c = Expression.Parameter(  
  9.         typeof( CompilerGeneratedDisplayClass ), "c" );  
  10.     Expression<Func<CompilerGeneratedDisplayClass, int>> field =  
  11.         Expression.Lambda<Func<CompilerGeneratedDisplayClass, int>>(  
  12.             Expression.Field(  
  13.                 c,  
  14.                 "x"  
  15.             ),  
  16.             new ParameterExpression[ ] { c }  
  17.         );  
  18. }  
  19.   
  20. // Calling a property  
  21. static void Property( ) {  
  22.     // Expression<Func<string, int>> prop = s => s.Length;  
  23.     ParameterExpression s = Expression.Parameter( typeofstring ), "s" );  
  24.     Expression<Func<stringint>> prop = Expression.Lambda<Func<stringint>>(  
  25.         Expression.Property(  
  26.             s,                                       // expression  
  27.             typeofstring ).GetProperty( "Length" ) // property  
  28.         ),  
  29.         new ParameterExpression[ ] { s }  
  30.     );  
  31. }  
  32.  
  33. #endregion  


方法/委托調用表達式部分
有兩點(diǎn)需要注意:

1、Expression.Call()對應的是方法調用,而Expression.Invoke()對應的是委托(delegate)的調用。它們在.NET中最大的不同可以說(shuō)是:一個(gè)委托背后的方法可能是某個(gè)類(lèi)上的方法,也可能是一個(gè)通過(guò)LCG(lightweight codegeneration)生成的方法;后者是不與任何類(lèi)相關(guān)聯(lián)的,所以調用機制會(huì )有點(diǎn)區別。在Expression treeAPI中這個(gè)區別就體現為工廠(chǎng)方法的不同。

2、Expression.Call()既對應成員方法的調用,也對應靜態(tài)方法的調用。調用靜態(tài)方法時(shí)把instance參數設為null。
C#代碼
  1. #region Invocation  
  2.   
  3. // Calling a static method  
  4. static void Call( ) {  
  5.     // Note that to call a static method, use Expression.Call(),  
  6.     // and set "instance" to null  
  7.   
  8.     // Expression<Func<string, int>> scall = s => int.Parse( s );  
  9.     ParameterExpression s = Expression.Parameter( typeofstring ), "s" );  
  10.     Expression<Func<stringint>> scall = Expression.Lambda<Func<stringint>>(  
  11.         Expression.Call(  
  12.             null,                      // instance  
  13.             typeofint ).GetMethod(   // method  
  14.                 "Parse"new Type[ ] { typeofstring ) } ),  
  15.             new Expression[ ] { s }    // arguments  
  16.         ),  
  17.         new ParameterExpression[ ] { s }  
  18.     );  
  19. }  
  20.   
  21. // Calling a member method  
  22. static void CallMember( ) {  
  23.     // Note that to call a member method, use Expression.Call(),  
  24.     // and set "instance" to the expression for the instance.  
  25.   
  26.     // Expression<Func<string, string>> mcall = s => s.ToUpper( );  
  27.     ParameterExpression s = Expression.Parameter( typeofstring ), "s" );  
  28.     Expression<Func<stringstring>> mcall = Expression.Lambda<Func<stringstring>>(  
  29.         Expression.Call(  
  30.             s,                                // instance  
  31.             typeofstring ).GetMethod(       // method  
  32.                 "ToUpper"new Type[ ] { } ),  
  33.             new Expression[ ] { }             // arguments  
  34.         ),  
  35.         new ParameterExpression[ ] { s }  
  36.     );  
  37. }  
  38.   
  39. // Invoking a delegate  
  40. static void Invoke( ) {  
  41.     // Note that invoking a delegate is different from calling a method.  
  42.     // Use Expression.Invoke() instead of Expression.Call().  
  43.   
  44.     // Expression<Func<Func<int>, int>> invoc = f => f( );  
  45.     ParameterExpression f = Expression.Parameter( typeof( Func<int> ), "f" );  
  46.     Expression<Func<Func<int>, int>> invoc = Expression.Lambda<Func<Func<int>, int>>(  
  47.         Expression.Invoke(  
  48.             f,                    // expression  
  49.             new Expression[ ] { } // arguments  
  50.         ),  
  51.         new ParameterExpression[ ] { f }  
  52.     );  
  53. }  
  54.  
  55. #endregion  


數組表達式部分
就是對數組下標和數組長(cháng)度的特殊處理,沒(méi)什么特別需要注意的。
C#代碼
  1. #region Array  
  2.   
  3. // Array index expression ("[]" operator on arrays)  
  4. static void ArrayIndex( ) {  
  5.     // Expression<Func<int[ ], int, int>> aryIdx = ( a, i ) => a[ i ];  
  6.     ParameterExpression a = Expression.Parameter( typeofint[ ] ), "a" );  
  7.     ParameterExpression i = Expression.Parameter( typeofint ), "i" );  
  8.     Expression<Func<int[ ], intint>> aryIdx = Expression.Lambda<Func<int[ ], intint>>(  
  9.         Expression.ArrayIndex(  
  10.             a, // array  
  11.             i  // index  
  12.         ),  
  13.         new ParameterExpression[ ] { a, i }  
  14.     );  
  15. }  
  16.   
  17. // Array length expression (".Length" property on arrays)  
  18. static void ArrayLength( ) {  
  19.     // Expression<Func<int[ ], int>> aryLen = a => a.Length;  
  20.     ParameterExpression a = Expression.Parameter( typeofint[ ] ), "a" );  
  21.     Expression<Func<int[ ], int>> aryLen = Expression.Lambda<Func<int[ ], int>>(  
  22.         Expression.ArrayLength(  
  23.             a // array  
  24.         ),  
  25.         new ParameterExpression[ ] { a }  
  26.     );  
  27. }  
  28.  
  29. #endregion  


新建對象表達式部分
基本上就是對應“new”運算符相關(guān)的表達式了。這部分有兩點(diǎn)需要注意:

1、與數組相關(guān)的兩個(gè)初始化方法:
Expression.NewArrayBounds()接受的參數是數組的元素類(lèi)型和數組的尺寸。尺寸可以是一維或多維的,取決于指定數組尺寸的表達式的個(gè)數。下面的例子里演示的是一個(gè)二維數組。注意到它是一個(gè)矩形數組而不是一個(gè)“數組的數組”(array-of-array,或者叫jagged array)。
Expression.NewArrayInit()方法對應的是數字的初始化器,例如new int[] { 1, 2, 3 };它接受的參數是數組的元素類(lèi)型和由初始化表達式組成的數組。

2、Expression.ListInit()并不只是能創(chuàng )建和初始化System.Collections.Generic.List<T>類(lèi)型的對象。任何能用C#3.0的列表初始化器表示的新建對象表達式都能用Expression.ListInit()表示,例如這個(gè):
C#代碼
  1. var hashset = new HashSet<string> {  
  2.     "Alpha""Beta""Charlie"  
  3. };  

要理解這個(gè)初始化器實(shí)際上被編譯器轉換為對默認構造器與一系列Add()方法的調用。在使用Expression.ListInit()時(shí)這些實(shí)際調用必須手工指定。下面的例子很明顯:先選擇了默認構造器并用一個(gè)Expression.New()來(lái)調用,然后是一組通過(guò)Expression.ElementInit()對Add()方法的調用。能夠制定調用的方法自然意味著(zhù)可以使用Add()以外的方法作為初始化器的內容咯。
C#代碼
  1. #region New  
  2.   
  3. // Creating a new object instance  
  4. static void New( ) {  
  5.     // Expression<Func<object>> n = ( ) => new object( );  
  6.     Expression<Func<object>> newObj = Expression.Lambda<Func<object>>(  
  7.         Expression.New(  
  8.             typeofobject ).GetConstructor( new Type[ ] { } ), // constructor  
  9.             new Expression[ ] { }                               // arguments  
  10.         ),  
  11.         new ParameterExpression[ ] { }  
  12.     );  
  13. }  
  14.   
  15. // Creating a new array with specified bounds  
  16. static void NewArrayBounds( ) {  
  17.     // Expression<Func<int[ , ]>> n = ( ) => new int[ 1, 2 ];  
  18.     Expression<Func<int[ , ]>> newArr = Expression.Lambda<Func<int[ , ]>>(  
  19.         Expression.NewArrayBounds(  
  20.             typeofint ),                               // type  
  21.             new Expression[ ] {                          // bounds  
  22.                 Expression.Constant( 1, typeofint ) ),  
  23.                 Expression.Constant( 2, typeofint ) )  
  24.             }  
  25.         ),  
  26.         new ParameterExpression[ ] { }  
  27.     );  
  28. }  
  29.   
  30. // Creating a new array with initializers  
  31. static void NewArrayInit( ) {  
  32.     // Expression<Func<int[ ]>> n = ( ) => new int[ ] { };  
  33.     Expression<Func<int[ ]>> newArrInit = Expression.Lambda<Func<int[ ]>>(  
  34.         Expression.NewArrayInit(  
  35.             typeofint ),        // type  
  36.             new Expression[ ] { } // initializers  
  37.         ),  
  38.         new ParameterExpression[ ] { }  
  39.     );  
  40. }  
  41.   
  42. // Creating a new list with initializers  
  43. static void ListInit( ) {  
  44.     // Expression<Func<List<int>>> n = ( ) => new List<int>( ) { 1, 2 };  
  45.     Expression<Func<List<int>>> linit = Expression.Lambda<Func<List<int>>>(  
  46.         Expression.ListInit(  
  47.             Expression.New(           // new expression  
  48.                 typeof( List<int> ).GetConstructor( new Type[ ] { } ),  
  49.                 new Expression[ ] { }  
  50.             ),  
  51.             new ElementInit[ ] {      // initializers  
  52.                 Expression.ElementInit(  
  53.                     typeof( List<int> ).GetMethod( "Add"new Type[ ] { typeofint ) } ),  
  54.                     new Expression[ ] { Expression.Constant( 1, typeofint ) ) }  
  55.                 ),  
  56.                 Expression.ElementInit(  
  57.                     typeof( List<int> ).GetMethod( "Add"new Type[ ] { typeofint ) } ),  
  58.                     new Expression[ ] { Expression.Constant( 2, typeofint ) ) }  
  59.                 )  
  60.             }  
  61.         ),  
  62.         new ParameterExpression[ ] { }  
  63.     );  
  64. }  
  65.  
  66. #endregion  


成員初始化表達式部分
對應物是C# 3.0中的成員初始化器;最常見(jiàn)的地方莫過(guò)于匿名類(lèi)型的實(shí)例的聲明了,例如:
C#代碼
  1. new { FistName = "John", LastName = "Smith" }  

為了演示方便,這里建了一個(gè)簡(jiǎn)單的內部類(lèi)。
C#代碼
  1. #region Member Initialization  
  2.   
  3. // simulates an anonymous type  
  4. private class DummyClass {  
  5.     public int Value { getset; }  
  6. }  
  7.   
  8. // Creating a new object instance with member initializers  
  9. static void MemberInit( ) {  
  10.     // Expression<Func<DummyClass>> memInit = ( ) => new { Value = 2 };  
  11.     Expression<Func<DummyClass>> minit = Expression.Lambda<Func<DummyClass>>(  
  12.         Expression.MemberInit(  
  13.             Expression.New(  
  14.                 typeof( DummyClass ).GetConstructor( new Type[ ] { } ),  
  15.                 new Expression[ ] { }  
  16.             ),  
  17.             new MemberBinding[ ] {  
  18.                 Expression.Bind(  
  19.                     typeof( DummyClass ).GetProperty( "Value" ),  
  20.                     Expression.Constant( 2, typeofint ) )  
  21.                 )  
  22.             }  
  23.         ),  
  24.         new ParameterExpression[ ] { }  
  25.     );  
  26. }  
  27.  
  28. #endregion  


“引用”表達式部分
這對于許多C#程序員來(lái)說(shuō)或許不是那么直觀(guān)的內容,不過(guò)如果了解Lisp的話(huà)就很好解釋。Expression.Quote()與Lisp中的quote特殊形式作用相似,作用是不對其操作數求值,而是將其操作數表達式作為結果的值。聽(tīng)起來(lái)有點(diǎn)拗口,我也說(shuō)不太清楚,或許舉個(gè)例子會(huì )容易理解一些。
假如我有一個(gè)lambda表達式,
C#代碼
  1. Func<int> five = ( ) => 2 + 3;  

然后調用five(),應該得到結果5。
但假如C#里有一種神奇的運算符(這里讓我用反單引號來(lái)表示),能夠阻止表達式的求值,那么下面的lambda表達式:
C#代碼
  1. Func<Expression> fiveExpr = ( ) = `( 2 + 3 );  

對fiveExpr()調用后得到的就是表示2+3的BinaryExpression。
這個(gè)Expression.Quote()所達到的效果也正是這一點(diǎn)。
C#代碼
  1. // Quoting an Expression  
  2. static void Quote( ) {  
  3.     // There‘s no equivalent syntax for quoting an Expression in C#.  
  4.     // The quote UnaryExpression is used for preventing the evaluation  
  5.     // of its operand expression. Semantically, this results in  
  6.     // returning its operand as the result of this unary expression,  
  7.     // as opposed to returning the evaluated value of its operand.  
  8.     //  
  9.     // It‘s rather like the quote special form in Lisp, where  
  10.     // <code>(quote datum)</code> evaluates to <code>datum</code>.  
  11.   
  12.     Expression<Func<BinaryExpression>> quote = Expression.Lambda<Func<BinaryExpression>>(  
  13.         Expression.Quote(  
  14.             Expression.Add(  
  15.                 Expression.Constant( 2.0 ),  
  16.                 Expression.Constant( 3.0 )  
  17.             )  
  18.         ),  
  19.         new ParameterExpression[ ] { }  
  20.     );  
  21.   
  22.     // Func<BinaryExpression> quteFunc = quote.Compile( );  
  23.     // Console.WriteLine( quoteFunc( ) ); // prints (2 + 3)  
  24.     //  
  25.     // In contrast, a normal Expression.Add() without the quote  
  26.     // will return 4 instead:  
  27.     //Expression<Func<int>> add = Expression.Lambda<Func<int>>(  
  28.     //    Expression.Add(  
  29.     //        Expression.Constant( 2.0 ),  
  30.     //        Expression.Constant( 3.0 )  
  31.     //    ),  
  32.     //    new ParameterExpression[ ] { }  
  33.     //);  
  34.     //Func<int> addFunc = add.Compile( );  
  35.     //Console.WriteLine( addFunc( ) ); // prints 5  
  36. }  


未說(shuō)明的工廠(chǎng)方法
這幾個(gè)工廠(chǎng)方法主要是用于自定義的表達式的,沒(méi)有C#的直觀(guān)的對應物,所以就不在這里說(shuō)明了。
C#代碼
  1. // not listed above:  
  2. //PropertyOrField  : MemberExpression  
  3. //MakeBinary       : BinaryExpression  
  4. //MakeMemberAccess : MemberExpression  
  5. //MakeUnary        : UnaryExpression  


Main()方法。演示一個(gè)稍微復雜一點(diǎn)的表達式
這段代碼的解釋放到代碼后。請先閱讀代碼看看:
C#代碼
  1.     static void Main( string[ ] args ) {  
  2.         // Let‘s make a little complex expression tree sample,  
  3.         // equivalent to:  
  4.         //Expression<Func<int[ ], int>> complexExpr =  
  5.         //    array => ( array != null && array.Length != 0 ) ?  
  6.         //        5 * ( 10 + array[ 0 ] ) :  
  7.         //        -1;  
  8.         ParameterExpression array = Expression.Parameter( typeofint[ ] ), "array" );  
  9.         Expression<Func<int[ ], int>> complexExpr = Expression.Lambda<Func<int[ ], int>>(  
  10.             Expression.Condition(  
  11.                 Expression.AndAlso(  
  12.                     Expression.NotEqual(  
  13.                         array,  
  14.                         Expression.Constant(  
  15.                             null  
  16.                         )  
  17.                     ),  
  18.                     Expression.NotEqual(  
  19.                         Expression.ArrayLength(  
  20.                             array  
  21.                         ),  
  22.                         Expression.Constant(  
  23.                             0,  
  24.                             typeofint )  
  25.                         )  
  26.                     )  
  27.                 ),  
  28.                 Expression.Multiply(  
  29.                     Expression.Constant(  
  30.                         5,  
  31.                         typeofint )  
  32.                     ),  
  33.                     Expression.Add(  
  34.                         Expression.Constant(  
  35.                             10,  
  36.                             typeofint )  
  37.                         ),  
  38.                         Expression.ArrayIndex(  
  39.                             array,  
  40.                             Expression.Constant(  
  41.                                 0,  
  42.                                 typeofint )  
  43.                             )  
  44.                         )  
  45.                     )  
  46.                 ),  
  47.                 Expression.Constant(  
  48.                     -1,  
  49.                     typeofint )  
  50.                 )  
  51.             ),  
  52.             new ParameterExpression[ ] { array }  
  53.         );  
  54.   
  55.         // And let‘s see it in action:  
  56.         Func<int[ ], int> func = complexExpr.Compile( );  
  57.         int[ ] arrayArg = new[ ] { 2, 3, 4, 5 };  
  58.         Console.WriteLine( func( arrayArg ) ); // prints 60  
  59.     }  
  60. }  

Main()方法里,我們手工構造了一個(gè)由基本表達式組裝起來(lái)的表達式。當然,我是可以把其中的各個(gè)子表達式先分別賦值給變量,避免這種巨大的嵌套調用;不過(guò)嵌套調用也有好處,那就是能比較直觀(guān)的與“樹(shù)形”聯(lián)系起來(lái)?;仡欉@個(gè)lambda表達式:
C#代碼
  1. Expression<Func<int[ ], int>> complexExpr =  
  2.     array => ( array != null && array.Length != 0 ) ?  
  3.         5 * ( 10 + array[ 0 ] ) :  
  4.         -1;  

它對應的抽象語(yǔ)法樹(shù)(AST)如下圖所示?;貞浧餉ST的特征,注意到用于改變表達式優(yōu)先順序的括號已經(jīng)不需要了:

這個(gè)AST與實(shí)際對Expression上的工廠(chǎng)方法的調用是一一對應的:

(圖片縮小了的話(huà)請點(diǎn)擊放大)
不難看出Expression tree與C#的表達式的關(guān)系。

Expression tree的Compile()方法的一個(gè)注意點(diǎn)

還是先看一個(gè)例子。我們要寫(xiě)一個(gè)比較奇怪的lambda表達式,并讓它變成一棵Expression tree:
C#代碼
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Linq.Expressions;  
  5.   
  6. static class Program {  
  7.     static void Main( string[ ] args ) {  
  8.         Expression<Func<List<int>, IEnumerable<int>>> filter =  
  9.             list => from i in list  
  10.                     where i % 2 == 0  
  11.                     select i;  
  12.         Console.WriteLine( filter );  
  13.         var fooList = new List<int> { 1, 2, 3, 4, 5 };  
  14.         var result = filter.Compile( )( fooList );  
  15.         foreach ( var i in result ) {  
  16.             Console.WriteLine( i );  
  17.         }  
  18.     }  
  19. }  

運行得到:
引用
list => list.Where(i => ((i % 2) = 0))
2
4


注意到那個(gè)查詢(xún)表達式(from...where...select...)會(huì )被翻譯為擴展方法的調用,所以上面代碼里的filter等價(jià)于:
C#代碼
  1. list => list.Where( i => i % 2 == 0 )  

也就是說(shuō)lambda表達式里面還嵌套有lambda表達式。
另外注意到List<T>實(shí)現了IEnumerable<T>而沒(méi)有實(shí)現IQueryable<T>,所以這個(gè)Where()方法是Enumerable類(lèi)上的。也就是說(shuō)filter等價(jià)于:
C#代碼
  1. list => Enumerable.Where<int>( list, i => i % 2 == 0 )  


然后讓我們把這棵Expression tree改用手工方式創(chuàng )建:
C#代碼
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Linq.Expressions;  
  5.   
  6. static class Program {  
  7.     static void Main( string[ ] args ) {  
  8.         ParameterExpression list = Expression.Parameter(typeof(List<int>), "list");  
  9.         ParameterExpression i = Expression.Parameter(typeof(int), "i");  
  10.         Expression<Func<List<int>, IEnumerable<int>>> filter = Expression.Lambda<Func<List<int>, IEnumerable<int>>>(  
  11.             Expression.Call(  
  12.                 typeof( Enumerable ).GetMethods( )  
  13.                     .First( method => "Where" == method.Name  
  14.                                    && 2 == method.GetParameters( ).Length )  
  15.                     .MakeGenericMethod( new [ ] { typeofint ) } ),  
  16.                 new Expression[ ] {  
  17.                     list,  
  18.                     Expression.Lambda<Func<intbool>>(  
  19.                         Expression.Equal(  
  20.                             Expression.Modulo(  
  21.                                 i,  
  22.                                 Expression.Constant(  
  23.                                     2,  
  24.                                     typeof(int)  
  25.                                 )  
  26.                             ),  
  27.                             Expression.Constant(  
  28.                                 0,  
  29.                                 typeof(int)  
  30.                             )  
  31.                         ),  
  32.                         new [ ] { i }  
  33.                     )  
  34.                 }  
  35.             ),  
  36.             new [ ] { list }  
  37.         );  
  38.         Console.WriteLine( filter );  
  39.         var fooList = new List<int> { 1, 2, 3, 4, 5 };  
  40.         var result = filter.Compile( )( fooList );  
  41.         foreach ( var item in result )  
  42.             Console.WriteLine( item );  
  43.     }  
  44. }  

留意一下我是如何通過(guò)反射來(lái)得到Enumerable.Where<TSource>>(thisIEnumerable<TSource> source, Func<TSource, bool>predicate)這個(gè)方法的MethodInfo的。由于Enumerable.Where()有兩個(gè)重載,而且都是publicstatic的,我們無(wú)法直接調用Type.GetMethod(string)來(lái)得到MethodInfo;另外,也無(wú)法通過(guò)Type.GetMethod(string,Type[])來(lái)得到這個(gè)MethodInfo,因為它是泛型方法定義的MethodInfo,不方便直接指定類(lèi)型。結果只好通過(guò)參數個(gè)數來(lái)區分兩個(gè)Enumerable.Where(),然后創(chuàng )建出Enumerable.Where<int>()的MethodInfo。

注意到,Enumerable.Where<int>()的第二個(gè)參數是Func<int, bool>類(lèi)型的,但我提供的參數數組里的卻是Expression<Func<int, bool>>類(lèi)型的。這樣能匹配么?
判斷標準很簡(jiǎn)單,只要參數數組里各項的Expression.Type與實(shí)際參數類(lèi)型匹配就能行。在調用Compile()的時(shí)候,即使有嵌套的lambda表達式(轉換成Expression tree也就是Expression<TDelegate>)也沒(méi)問(wèn)題。
Expression<Func<int, bool>>的Type屬性返回的就是Func<int, bool>,與Where()需要的參數類(lèi)型匹配,OK。

沒(méi)注意到的話(huà)一開(kāi)始可能會(huì )被轉暈掉,所以我覺(jué)得值得一提。

LINQ Expression tree與靜態(tài)類(lèi)型

LINQ Expression tree是靜態(tài)類(lèi)型的,上面的例子里我都選用了顯式指定類(lèi)型的版本的API來(lái)創(chuàng )建樹(shù)的節點(diǎn)(特別是Expression.Constant(),其實(shí)不指定類(lèi)型也可以的)。
雖然Expression tree的內容是靜態(tài)類(lèi)型的,但仔細觀(guān)察會(huì )發(fā)現組裝表達式時(shí),參數類(lèi)型基本上都只要求是Expression或其派生類(lèi)就行,無(wú)法避免在組裝時(shí)把不匹配的表達式錯誤的組裝到一起。為什么會(huì )這樣呢?
對編譯器有所了解的人應該很清楚,把源代碼解析到抽象語(yǔ)法樹(shù)只是完成了語(yǔ)法分析,之后還需要做語(yǔ)義分析。語(yǔ)義分析就包括了類(lèi)型檢查等工作。表達式的一個(gè)重要特征就是可組合性,一個(gè)表達式的子表達式可以是任意語(yǔ)法結構的表達式;類(lèi)型的匹配與否無(wú)法通過(guò)語(yǔ)法來(lái)表現。當我們把一個(gè)lambda表達式賦值給一個(gè)Expressin<TDelegate>類(lèi)型的變量時(shí),C#編譯器做了類(lèi)型檢查,并且生成了相應的Expressiontree。但當我們手工創(chuàng )建Expressiontree時(shí),我們既獲得了創(chuàng )建并組裝節點(diǎn)的權利,也承擔起了檢查類(lèi)型的義務(wù)——C#編譯器只知道那些是表示表達式的對象,而無(wú)法進(jìn)一步幫忙檢查其中的內容是否匹配。所以,在創(chuàng )建Expression tree時(shí)需要額外小心,并且要注意檢查實(shí)際內容的類(lèi)型是否匹配。
一般來(lái)說(shuō)這并不是大問(wèn)題,因為Expression tree一般是由編譯器前端所生成的。在生成這棵樹(shù)之前,編譯器就應該負責完成類(lèi)型檢查等工作。

再談LINQ Expression tree的局限性

LINQ的Expressiontree只能用于表示表達式,而且并不支持C#與VB.NET的所有表達式——與賦值相關(guān)的表達式都無(wú)法用Expressiontree表示。因此雖然有一元加和一元減這兩個(gè)一元運算符的對應物,卻沒(méi)有同為一元運算符的遞增(++)與遞減(--)的對應物。同時(shí),Expressiontree里面也沒(méi)有“變量”的概念,ParameterExpression只是用來(lái)表示參數,而參數的值在實(shí)際調用時(shí)綁定好之后就不能再改變。

但這些限制并沒(méi)有降低LINQ Expression tree理論上所能表示的計算邏輯的范圍。

1、引用透明性

由于沒(méi)有“變量”的概念,通過(guò)Expression tree定義的表達式本身無(wú)法產(chǎn)生副作用,因而只要一棵Expression tree中不包含對外部的有副作用的方法的調用(Invoke/Call),其中的任何子樹(shù)重復多次產(chǎn)生的值都是一樣的。

這種性質(zhì)被稱(chēng)為引用透明性(referential transparency)。舉例來(lái)說(shuō),假如原本有這樣的一組表達式:
Java代碼
  1. a = 1  
  2. b = 2  
  3. x = a + b  
  4. y = a - b  
  5. result = x * y - x % y  

請把這些表達式中的符號看成“名字到值的綁定”而不是變量。如果有引用透明性,那么上面的表達式的求值就可以使用所謂“代替模型”(substitution model),可以展開(kāi)為以下形式而不改變原表達式計算出來(lái)的結果:
Java代碼
  1. result = (1 + 2) * (1 - 2) - (1 + 2) % (1 - 2)  

同理,當我們實(shí)在需要在同一棵Expression tree中多次使用同一個(gè)子表達式的計算結果時(shí),只要多次使用同一棵子樹(shù)即可;既然沒(méi)有變量來(lái)暫時(shí)記住中間結果,那么就手動(dòng)把表達式展開(kāi)。用Expression tree的例子來(lái)說(shuō)明,那就是:
C#代碼
  1. // xPlusY = x + y  
  2. // result = xPlusY * xPlusY  
  3.   
  4. var x = Expression.Parameter( typeofint ), "x" );  
  5. var y = Expression.Parameter( typeofint ), "y" );  
  6. var add = Expression.Add( x, y );  
  7. var result = Expression.Lambda<Func<intintint>>(  
  8.     Expression.Multiply( add, add ),  
  9.     new ParameterExpression[ ] { x, y }  
  10. );  
  11. Console.WriteLine( result.Compile( )( 3, 4 ) ); // prints 49  

(前面已經(jīng)介紹過(guò)Expression tree的工廠(chǎng)方法,這里為了書(shū)寫(xiě)方便就不再顯式指明變量類(lèi)型了。)
能夠通過(guò)代替模型來(lái)求值是許多函數式語(yǔ)言的特征之一。求值順序不影響計算結果,一般有兩種求值順序:如果先求值再代替,稱(chēng)為應用序(applicative order),也叫做緊迫計算(eager evaluation)或者嚴格求值(strictevaluation);如果先替換在求值,則稱(chēng)為正則序(normal order),也叫做惰性求值(lazyevaluation)或者延遲求值(delayed evaluation)。
在LINQ Expression tree中,因為無(wú)法使用變量,也就難以方便的進(jìn)行嚴格求值;上面的例子手工展開(kāi)了表達式,實(shí)際上就是模擬了延遲求值的求值過(guò)程,在執行效率上會(huì )比嚴格求值要差一些。這雖然不影響計算的能力,但從性能角度看這么做是有負面影響的。

如果一棵Expressiontree中含有對外界的調用,上述的引用透明性就不成立了;我們無(wú)法確定一個(gè)調用是否含有副作用,所以無(wú)法保證不同的求值順序能得到相同的結果。而這個(gè)問(wèn)題需要特別的注意,因為.NET/CLR的類(lèi)型系統中沒(méi)任何有信息能表明一個(gè)函數是否有副作用,所以只能悲觀(guān)的假設包含對外界的調用的Expression tree不滿(mǎn)足引用透明性。

2、Lambda表達式

LINQ Expressiontree允許定義與調用lambda表達式,甚至可以在表達式之中嵌套的定義lambda表達式。這奠定了Expressiontree理論上具有接近完備計算能力的基礎。所謂“完備”是指圖靈完備(Turing-complete)。無(wú)類(lèi)型的lambda演算是圖靈完備的,但在C#中lambda表達式需要指明類(lèi)型,而有些類(lèi)型通過(guò)C#的類(lèi)型系統難以表示,因此其表達力會(huì )比無(wú)類(lèi)型lambda演算要弱一些。
由于C#的類(lèi)型系統允許定義遞歸類(lèi)型,我們可以利用C#的lambda表達式來(lái)寫(xiě)遞歸的函數。同時(shí),方法體只是一個(gè)表達式(而不是語(yǔ)句塊)的lambda表達式可以用Expression tree表示,也就是說(shuō)我們可以用Expressiontree來(lái)寫(xiě)遞歸函數。有了遞歸,原本需要循環(huán)的邏輯都能用遞歸來(lái)編寫(xiě),也就突破了LINQ Expressiontree沒(méi)有循環(huán)結構的限制。下一篇就讓我們來(lái)看看實(shí)例,敬請期待 ^ ^
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
C# Lambda表達式詳解,及Lambda表達式樹(shù)的創(chuàng )建
利用C#將Lambda表達式轉化成Expression樹(shù)
C#-表達式樹(shù)
由淺入深表達式樹(shù)(一)
Linq之Expression高級篇(常用表達式類(lèi)型)
打造自己的LINQ Provider(上):Expression Tree揭秘
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久