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

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

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

開(kāi)通VIP
LINQ與DLR的Expression tree(5):用lambda表達式表示常見(jiàn)控制結構 (轉 rednaxelafx.javaeye.com)

LINQ與DLR的Expression tree(5):用lambda表達式表示常見(jiàn)控制結構

關(guān)鍵字: linq expression tree recursive lambda control structure
(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)控制結構


LINQ Expression tree能直接表示的語(yǔ)法結構在上一篇中已經(jīng)詳細的列了出來(lái),包括算術(shù)、按位、邏輯等運算符的表達式、條件表達式、方法調用表達式、對象創(chuàng )建表達式等。要表示一般的命令式程序,需要支持3中基本控制流語(yǔ)法結構:順序、分支、循環(huán)。在C#中這三種結構能很自然的用語(yǔ)句來(lái)表示,但有語(yǔ)句的lambda表達式無(wú)法用LINQ Expressiontree表示。下面就讓我們來(lái)看看這三種結構如何轉換成只用表達式的方式來(lái)表示。

需要事先說(shuō)明三點(diǎn):
1、只要避免使用賦值相關(guān)的表達式,一個(gè)只包含表達式的lambda表達式既可以轉換為委托也可以轉換為Expressiontree;手工創(chuàng )建Expressiontree比較麻煩,本文的例子無(wú)特別說(shuō)明都將通過(guò)轉換為委托的lambda表達式來(lái)表示,轉換為Expressiontree的版本留待后續文章再詳細給出。
2、能夠用Expression tree表示的東西不一定能被所有LINQ provider接受。這點(diǎn)必須注意。也就是說(shuō)即使能把一個(gè)語(yǔ)句塊變成一個(gè)表達式,也未必能用在LINQ to SQL等場(chǎng)景里。
3、下面演示的轉換方式絕對不代表任何best practice;.NET中方法調用的開(kāi)銷(xiāo)是不可忽視的,因而轉換后的表達式肯定會(huì )比原本的語(yǔ)句慢。本文只是著(zhù)重說(shuō)明轉換的可能性。

局部變量的模擬

局部變量,顧名思義,在方法外是看不到的;方法調用結束后局部變量也就隨即消失(如果不涉及閉包)。它們的作用主要是保存一些中間的計算結果,將很長(cháng)的表達式分割成一些比較短的表達式,使得程序代碼更為清晰。一般在C#中使用局部變量需要聲明語(yǔ)句和賦值表達式,而這兩種結構LINQExpression tree都無(wú)法支持。怎么辦呢?

許多情況下可以把局部變量去掉,把短表達式拼接回到長(cháng)的表達式,避免使用語(yǔ)句。一個(gè)簡(jiǎn)單的例子:
C#代碼
  1. int x, int y ) => {  
  2.     var strX = x.ToString( "X" );  
  3.     var strY = y.ToString( "x" );  
  4.     Console.WriteLine( "x = {0}, y = {1}", strX, strY );  
  5. }  

可以很順利的變成:
C#代碼
  1. int x, int y ) =>  
  2.     Console.WriteLine( "x = {0}, y = {1}", x.ToString( "X" ), y.ToString( "x" ) )  


但這是不是唯一的選擇呢?或許計算某個(gè)中間結果的開(kāi)銷(xiāo)很大,而后面的計算中要多次用到它;或許計算某個(gè)中間結果會(huì )對產(chǎn)生副作用,而我們只希望副作用發(fā)生一次;有許多情況下我們還是需要局部變量的。怎么辦呢?

注意到,LINQ Expression tree雖然不支持聲明局部變量,卻允許聲明和調用嵌套的lambda表達式。將中間的計算結果以參數的形式傳給一個(gè)嵌套的lambda表達式,也就等同于使用了局部變量。例子:
C#代碼
  1. ( ) => {  
  2.     var input = Console.ReadLine( );  
  3.     var lowerCase = input.ToLower( );  
  4.     var upperCase = input.ToUpper( );  
  5.     Console.WriteLine( "lower case: {0}\nupper case: {1}", lowerCase, upperCase );  
  6. }  

變成:
C#代碼
  1. ( ) => ( ( Action<string> ) ( s =>  
  2.         Console.WriteLine( "lower case: {0}\nupper case: {1}",  
  3.             s.ToLower( ), s.ToUpper( ) )  
  4.     ) )( Console.ReadLine( ) )  

注意到Console.ReadLine()是有副作用的,這個(gè)方法調用會(huì )消耗掉輸入流里的一行,顯然我們不希望調用它兩次。
將語(yǔ)句轉換為表達式之后,原本寫(xiě)在前面的語(yǔ)句變成寫(xiě)在后面的表達式了,不習慣的話(huà)看起來(lái)或許很不自然,但注意到C#采用了嚴格求值,要先把參數的值求出來(lái)之后才執行方法調用,所以轉換后的寫(xiě)法的執行順序與轉換前是一致的。
例子中的強制類(lèi)型轉換((Action<string>))是必要的,編譯器需要它才知道該生成委托還是Expressiontree。實(shí)際上只要最外層的lambda表達式是賦值給Expression<TDelegate>類(lèi)型的變量,整個(gè)lambda表達式(包括內層嵌套的)都會(huì )生成為Expression tree,像這樣:
C#代碼
  1. Expression<Action> expr = ( ) => ( ( Action<string> ) ( s =>  
  2.     Console.WriteLine( "lower case: {0}\nupper case: {1}",  
  3.         s.ToLower( ), s.ToUpper( ) )  
  4. ) )( Console.ReadLine( ) );  

會(huì )由編譯器生成為:
C#代碼
  1. var s = Expression.Parameter( typeofstring ), "s" );  
  2. Expression<Action> expr = Expression.Lambda<Action>(  
  3.     Expression.Invoke(  
  4.         Expression.Convert(  
  5.             Expression.Lambda<Action<string>>(  
  6.                 Expression.Call(  
  7.                     null,  
  8.                     typeof( Console ).GetMethod(  
  9.                         "WriteLine",  
  10.                         new Type[ ] {  
  11.                             typeofstring ),  
  12.                             typeofobject ),  
  13.                             typeofobject )  
  14.                         }  
  15.                     ),  
  16.                     new Expression[ ] {  
  17.                         Expression.Constant(  
  18.                             "lower case: {0}\nupper case: {1}",  
  19.                             typeofstring )  
  20.                         ),  
  21.                         Expression.Call(  
  22.                             s,  
  23.                             typeofstring ).GetMethod( "ToLower", Type.EmptyTypes ),  
  24.                             new Expression[ 0 ]  
  25.                         ),  
  26.                         Expression.Call(  
  27.                             s,  
  28.                             typeofstring ).GetMethod( "ToUpper", Type.EmptyTypes ),  
  29.                             new Expression[ 0 ]  
  30.                         )  
  31.                     }  
  32.                 ),  
  33.                 new [ ] { s }  
  34.             ),  
  35.             typeof( Action<string> )  
  36.         ),  
  37.         new Expression[] {  
  38.             Expression.Call(  
  39.                 null,  
  40.                 typeof( Console ).GetMethod( "ReadLine", Type.EmptyTypes ),  
  41.                 new Expression[ 0 ]  
  42.             )  
  43.         }  
  44.     ),  
  45.     new ParameterExpression[ 0 ]  
  46. );  

注意到里面嵌套的lambda表達式也被編譯為Expression tree而不是一個(gè)委托。如果手工創(chuàng )建這棵Expressiontree則可以省去類(lèi)型轉換的那步,也就是等同于將上述代碼的第4、35、36這三行注釋掉,因為那個(gè)類(lèi)型轉換本身并沒(méi)有意義,只是為了讓編譯器得到足夠的類(lèi)型信息來(lái)轉換lambda表達式而已。

順序結構的模擬

語(yǔ)句與表達式最大的區別就是前者一般沒(méi)有值或忽略值,而后者一定有值。因而語(yǔ)句只能通過(guò)分隔符一個(gè)個(gè)按順序寫(xiě),而不能像表達式可以用運算符結合起來(lái)或作為參數傳遞。在用表達式模擬順序結構時(shí),最大的障礙就是返回值類(lèi)型為void的方法——它們不返回任何值,無(wú)法放在表達式里與表達式的其它部分組合起來(lái)。如果能有辦法把void變成null也好……所謂“遇到問(wèn)題的時(shí)候只要增加一個(gè)間接層就能解決”

而.NET就提供了這么一種辦法。所有委托的基類(lèi),Delegate類(lèi)上有一個(gè)DynamicInvoke()方法,參數類(lèi)型是paramsobject[],返回值類(lèi)型是object,正好滿(mǎn)足我們的需要。于是像Console.WriteLine()這種返回void的方法,可以包裝為一個(gè)lambda表達式,然后用DynamicInvoke()包裝起來(lái):
C#代碼
  1. ( ( Action ) ( ( ) => Console.WriteLine( ) ) ).DynamicInvoke( )  

這樣的調用將總是返回null,因為Action系的委托忽略返回值,而Delegate.DynamicInvoke()對返回值類(lèi)型為void的委托類(lèi)型總是返回null。這樣就有機會(huì )用到C#里方便的??運算符把語(yǔ)句變成表達式串起來(lái)了——??運算符是一個(gè)具有短路求值性質(zhì)的運算符,語(yǔ)義是:當左操作數不為null時(shí)值為左操作數的值,否則為右操作數的值。舉例來(lái)說(shuō),把這兩個(gè)語(yǔ)句:
C#代碼
  1. Console.WriteLine( "1" );  
  2. Console.WriteLine( "2" );  

變成:
C#代碼
  1. ( ( Action ) ( ( ) => Console.WriteLine( "1" ) ) ).DynamicInvoke( ) ??  
  2. ( ( Action ) ( ( ) => Console.WriteLine( "2" ) ) ).DynamicInvoke( )  


把這種轉換方式應用在lambda表達式里,就可以把這個(gè)帶有語(yǔ)句塊的lambda表達式:
C#代碼
  1. ( ) => {  
  2.     var s = Console.ReadLine( );  
  3.     Console.WriteLine( s.ToLower( ) );  
  4.     Console.WriteLine( s.ToUpper( ) );  
  5. }  

(注意這里的s是一個(gè)局部變量)
變成一個(gè)只有表達式的lambda表達式:
C#代碼
  1. ( ) =>  
  2.     ( ( Func<stringobject> ) ( s => (  
  3.         ( ( Action ) ( ( ) => Console.WriteLine( s.ToLower( ) ) ) ).DynamicInvoke( ) ??  
  4.         ( ( Action ) ( ( ) => Console.WriteLine( s.ToUpper( ) ) ) ).DynamicInvoke( ) )  
  5.     ) )( Console.ReadLine( ) )  

這個(gè)lambda表達式就能夠被LINQ Expression tree所表示了。
留意一下這個(gè)例子里的s,在最內層的lambda表達式里是不是參數也不是局部變量,而是自由變量,體現了C#的lambda表達式具有閉包的功能。如果沒(méi)有閉包的功能,s就得出現在每個(gè)最內層lambda表達式的參數表里,那就麻煩了。

分支結構的模擬

最基本的分支結構是if-else語(yǔ)句,對應的有?:運算符表示的條件表達式。這兩者看似能直接對應,語(yǔ)句與表達式的區別再次體現了出來(lái):語(yǔ)句沒(méi)有或忽略值,而表達式必須有值。因而,if語(yǔ)句可以沒(méi)有else子句,也不關(guān)心返回值的問(wèn)題;但條件表達式必須同時(shí)有true和false的分支,且兩個(gè)分支的值的類(lèi)型必須匹配。舉例來(lái)說(shuō):
C#代碼
  1. static int Abs( int x ) {  
  2.     if ( 0 > x ) return -x;  
  3.     else return x;  
  4. }  

很容易變?yōu)楸磉_式:
C#代碼
  1. int x ) => ( 0 > x ) ? -x : x  

但這個(gè)函數就無(wú)法直接表示為表達式了:
C#代碼
  1. static void PrintIfEven( int x ) {  
  2.     if ( 0 == x % 2 ) Console.WriteLine( x );  
  3. }  

要轉換,就需要應用到上一節提到的包裝技巧:
C#代碼
  1. int x ) => ( 0 == x % 2 ) ?  
  2.     ( ( Action ) ( ( ) => Console.WriteLine( x ) ) ).DynamicInvoke( ) :  
  3.     null  

再次注意到閉包的應用:最內層的lambda表達式使用了自由變量x。

switch語(yǔ)句可以看作是if-else串起來(lái),轉換為表達式的話(huà),串聯(lián)使用條件表達式就行,有需要的時(shí)候加上包裝。例如:
C#代碼
  1. static string Grade( int point ) {  
  2.     switch ( point / 10 ) {  
  3.     case 10:  
  4.     case 9:  
  5.         return "A";  
  6.     case 8:  
  7.         return "B";  
  8.     case 7:  
  9.         return "C";  
  10.     case 6:  
  11.         return "D";  
  12.     default:  
  13.         return "F";  
  14.     }  
  15. }  

簡(jiǎn)單的變成:
C#代碼
  1. int point ) => ( ( Func<intstring> ) ( i =>  
  2.     ( 9 == i || 10 == i ) ? "A" :  
  3.     ( 8 == i ) ? "B" :  
  4.     ( 7 == i ) ? "C" :  
  5.     ( 6 == i ) ? "D" :  
  6.     /* else */   "F"  


循環(huán)結構的模擬

用命令式語(yǔ)言的思維方式,循環(huán)語(yǔ)句無(wú)法轉換為表達式。但我們可以一步步來(lái)尋找突破口。
首先找出循環(huán)本質(zhì)上需要怎樣的支持。有兩點(diǎn):1、需要有終止條件;2、需要能夠在一輪循環(huán)結束后讓控制流跳轉回到循環(huán)體的開(kāi)始處。另外,大多循環(huán)還需要用到循環(huán)變量,要能夠更新循環(huán)變量的值。
假如不能使用局部變量來(lái)做循環(huán)變量,回想到本文開(kāi)頭提到的轉換局部變量的方法,可以把循環(huán)變量放在參數里,把循環(huán)體變成一個(gè)函數。這樣,循環(huán)就變成遞歸的形式了,這也正好解決了控制流跳轉的問(wèn)題。事實(shí)上在函數式語(yǔ)言里,迭代(iteration)就是用這樣的遞歸來(lái)實(shí)現的。
于是,如何把循環(huán)語(yǔ)句轉換為表達式的問(wèn)題就變成了如何用lambda表達式表示遞歸函數的問(wèn)題。問(wèn)題是,lambda表達式?jīng)]有名字——它就是匿名函數。沒(méi)有名字的話(huà),如何遞歸呢?肯定會(huì )有人想到這種做法:
C#代碼
  1. Func<intint> factorial = null;  
  2. factorial = x => ( 0 == x ) ? 1 : x * factorial( x - 1 );  

在C#里這是可行的,但不徹底。這里我們要用的辦法,是通過(guò)找到一個(gè)函數的不動(dòng)點(diǎn)(fix-point)來(lái)實(shí)現lambda表達式的遞歸。具體的原理留待以后的文章再詳細討論,這里先給出結果來(lái)滿(mǎn)足一下眼球。通過(guò)這樣一個(gè)輔助類(lèi):
C#代碼
  1. delegate T SelfApplicable<T>( SelfApplicable<T> func );  
  2.   
  3. public static class Functional<T, TR> {  
  4.     private static readonly  
  5.         SelfApplicable<Func<Func<Func<T, TR>, Func<T, TR>>, Func<T, TR>>> _yCombinator =  
  6.             y => f => x => f( y( y )( f ) )( x );  
  7.     private static readonly  
  8.         Func<Func<Func<T, TR>, Func<T, TR>>, Func<T, TR>> _fixPointGenerator =  
  9.             _yCombinator( _yCombinator );  
  10.   
  11.     public static Func<Func<Func<T, TR>, Func<T, TR>>, Func<T, TR>> Fix {  
  12.         get { return _fixPointGenerator; }  
  13.     }  
  14. }  

我們可以做到這種效果:
C#代碼
  1. Func<intint> factorial = Functional<intint>.Fix(  
  2.     fac => x => ( 0 == x ) ? 1 : x * fac( x - 1) );  
  3. factorial( 5 ); // 120  


注意到這種做法只用了lambda表達式,所以也可以轉換為使用Expression tree來(lái)完成整個(gè)過(guò)程。把上述輔助類(lèi)里有效的內容提取出來(lái),我們來(lái)看看只用Expression tree實(shí)現的版本:
C#代碼
  1. using System;  
  2. using System.Linq.Expressions;  
  3.   
  4. static class TestRecursiveExpressionTree {  
  5.     static void Main( string[ ] args ) {  
  6.         ExpressionTreeTest( 5 ); // prints 120  
  7.         LambdaTest( 4 );         // prints 24  
  8.     }  
  9.   
  10.     delegate T SelfApplicableExpr<T>( Expression<SelfApplicableExpr<T>> self );  
  11.   
  12.     static void ExpressionTreeTest( int num ) {  
  13.         // parameters  
  14.         var y = Expression.Parameter(  
  15.             typeof(  
  16.                 Expression<SelfApplicableExpr<  
  17.                     Expression<Func<  
  18.                         Expression<Func<  
  19.                             Expression<Func<intint>>,  
  20.                             Expression<Func<intint>>  
  21.                         >>,  
  22.                         Expression<Func<intint>>  
  23.                     >>  
  24.                 >>  
  25.             ),  
  26.             "y"  
  27.         );  
  28.         var f = Expression.Parameter(  
  29.             typeof(  
  30.                 Expression<Func<  
  31.                     Expression<Func<intint>>,  
  32.                     Expression<Func<intint>>  
  33.                 >>  
  34.             ),  
  35.             "f"  
  36.         );  
  37.         var x = Expression.Parameter( typeofint ), "x" );  
  38.         var fac = Expression.Parameter( typeof( Expression<Func<intint>> ), "fac" );  
  39.   
  40.         // Y Combinator  
  41.         var Y = Expression.Lambda<SelfApplicableExpr<  
  42.             Expression<Func<  
  43.                 Expression<Func<  
  44.                     Expression<Func<intint>>,  
  45.                     Expression<Func<intint>>  
  46.                 >>,  
  47.                 Expression<Func<intint>>  
  48.             >>  
  49.         >>(  
  50.             Expression.Quote(  
  51.                 Expression.Lambda<  
  52.                     Func<  
  53.                         Expression<Func<  
  54.                             Expression<Func<intint>>,  
  55.                             Expression<Func<intint>>  
  56.                         >>,  
  57.                         Expression<Func<intint>>  
  58.                     >  
  59.                 >(  
  60.                     Expression.Quote(  
  61.                         Expression.Lambda<Func<intint>>(  
  62.                             Expression.Invoke(  
  63.                                 Expression.Call(  
  64.                                     Expression.Invoke(  
  65.                                         Expression.Call(  
  66.                                             f,  
  67.                                             typeof(  
  68.                                                 Expression<Func<  
  69.                                                     Expression<Func<intint>>,  
  70.                                                     Expression<Func<intint>>  
  71.                                                 >>  
  72.                                             ).GetMethod( "Compile" ),  
  73.                                             new Expression[ ] { }  
  74.                                         ),  
  75.                                         new Expression[ ] {  
  76.                                             Expression.Invoke(  
  77.                                                 Expression.Call(  
  78.                                                     Expression.Invoke(  
  79.                                                         Expression.Call(  
  80.                                                             y,  
  81.                                                             typeof(  
  82.                                                                 Expression<SelfApplicableExpr<  
  83.                                                                     Expression<Func<  
  84.                                                                         Expression<Func<  
  85.                                                                             Expression<Func<intint>>,  
  86.                                                                             Expression<Func<intint>>  
  87.                                                                         >>,  
  88.                                                                         Expression<Func<intint>>  
  89.                                                                     >>  
  90.                                                                 >>  
  91.                                                             ).GetMethod( "Compile" ),  
  92.                                                             new Expression[ ] { }  
  93.                                                         ),  
  94.                                                         new Expression[ ] { y }  
  95.                                                     ),  
  96.                                                     typeof(  
  97.                                                         Expression<Func<  
  98.                                                             Expression<Func<  
  99.                                                                 Expression<Func<intint>>,  
  100.                                                                 Expression<Func<intint>>  
  101.                                                             >>,  
  102.                                                             Expression<Func<intint>>  
  103.                                                         >>  
  104.                                                     ).GetMethod( "Compile" ),  
  105.                                                     new Expression[ ] { }  
  106.                                                 ),  
  107.                                                 new Expression[ ] { f }  
  108.                                             )  
  109.                                         }  
  110.                                     ),  
  111.                                     typeof(  
  112.                                         Expression<Func<intint>>  
  113.                                     ).GetMethod( "Compile" ),  
  114.                                     new Expression[ ] { }  
  115.                                 ),  
  116.                                 new Expression[ ] { x }  
  117.                             ),  
  118.                             new ParameterExpression[ ] { x }  
  119.                         )  
  120.                     ),  
  121.                     new ParameterExpression[ ] { f }  
  122.                 )  
  123.             ),  
  124.             new ParameterExpression[ ] { y }  
  125.         );  
  126.   
  127.         // Fix-point finder  
  128.         var Fix = Y.Compile( )( Y );  
  129.   
  130.         // Factorial helper  
  131.         var F = Expression.Lambda<  
  132.             Func<  
  133.                 Expression<Func<intint>>,  
  134.                 Expression<Func<intint>>  
  135.             >  
  136.         >(  
  137.             Expression.Quote(  
  138.                 Expression.Lambda<Func<intint>>(  
  139.                     Expression.Condition(  
  140.                         Expression.Equal(    // test  
  141.                             x,  
  142.                             Expression.Constant(  
  143.                                 0,  
  144.                                 typeofint )  
  145.                             )  
  146.                         ),  
  147.                         Expression.Constant( // if true  
  148.                             1,  
  149.                             typeofint )  
  150.                         ),  
  151.                         Expression.Multiply( // if false  
  152.                             x,  
  153.                             Expression.Invoke(  
  154.                                 Expression.Call(  
  155.                                     fac,  
  156.                                     typeof( Expression<Func<intint>> ).GetMethod( "Compile" ),  
  157.                                     new Expression[ ] { }  
  158.                                 ),  
  159.                                 new Expression[ ] {  
  160.                                     Expression.Subtract(  
  161.                                         x,  
  162.                                         Expression.Constant(  
  163.                                             1,  
  164.                                             typeofint )  
  165.                                         )  
  166.                                     )  
  167.                                 }  
  168.                             )  
  169.                         )  
  170.                     ),  
  171.                     new ParameterExpression[ ] { x }  
  172.                 )  
  173.             ),  
  174.             new ParameterExpression[ ] { fac }  
  175.         );  
  176.   
  177.         // Factorial expression tree  
  178.         var factorial = Fix.Compile( )( F );  
  179.   
  180.         // call the expression tree  
  181.         Console.WriteLine( factorial.Compile( )( num ) );  
  182.     }  
  183.   
  184.     static void LambdaTest( int num ) {  
  185.         // Y Combinator  
  186.         Expression<SelfApplicableExpr<  
  187.             Expression<Func<  
  188.                 Expression<Func<  
  189.                     Expression<Func<intint>>,  
  190.                     Expression<Func<intint>>  
  191.                 >>,  
  192.                 Expression<Func<intint>>  
  193.             >>  
  194.         >> Y =  
  195.             y => f => x => f.Compile( )( y.Compile( )( y ).Compile( )( f ) ).Compile( )( x );  
  196.   
  197.         // Fix-point finder  
  198.         Expression<Func<  
  199.             Expression<Func<  
  200.                 Expression<Func<intint>>,  
  201.                 Expression<Func<intint>>  
  202.             >>,  
  203.             Expression<Func<intint>>  
  204.         >> Fix = Y.Compile( )( Y );  
  205.         // or just: var Fix = Y.Compile( )( Y );  
  206.   
  207.         // Factorial helper  
  208.         Expression<Func<  
  209.             Expression<Func<intint>>,  
  210.             Expression<Func<intint>>  
  211.         >> F = fac => x => x == 0 ? 1 : x * fac.Compile( )( x - 1 );  
  212.   
  213.         // Factorial expression tree  
  214.         Expression<Func<intint>> factorial = Fix.Compile( )( F );  
  215.         // or just: var factorial = Fix.Compile( )( F );  
  216.   
  217.         // call the expression tree  
  218.         Console.WriteLine( factorial.Compile( )( num ) );  
  219.     }  
  220. }  

上面的例子里,前一個(gè)版本的Expression tree是手工創(chuàng )建的,后一個(gè)版本的是由編譯器從lambda表達式轉換來(lái)的。原理另外再解釋?zhuān)信d趣的話(huà)先運行上面的例子看看吧。
上面這個(gè)例子如果把整個(gè)遞歸函數寫(xiě)在一個(gè)lambda表達式里的話(huà),類(lèi)型和內容都會(huì )簡(jiǎn)單些,不用Compile()那么多次……嘛,不管了,總之現在這樣也能運行。

再看順序結構的模擬

既然能模擬出循環(huán)的效果,讓我們回頭看看前面的一個(gè)例子:
C#代碼
  1. ( ) =>  
  2.     ( ( Func<stringobject> ) ( s => (  
  3.         ( ( Action ) ( ( ) => Console.WriteLine( s.ToLower( ) ) ) ).DynamicInvoke( ) ??  
  4.         ( ( Action ) ( ( ) => Console.WriteLine( s.ToUpper( ) ) ) ).DynamicInvoke( ) )  
  5.     ) )( Console.ReadLine( ) )  

很明顯,DynamicInvoke()與??的包裝部分是重復的。能把它抽象出來(lái)么?

為了方便,先定義一個(gè)輔助類(lèi):
C#代碼
  1. delegate T SelfApplicable<T>( SelfApplicable<T> func );  
  2.   
  3. public static class Functional<T1, T2, TR> {  
  4.     private static readonly  
  5.         SelfApplicable<Func<Func<Func<T1, T2, TR>, Func<T1, T2, TR>>, Func<T1, T2, TR>>>  
  6.             _yCombinator =  
  7.                 y => f => ( a, b ) => f( y( y )( f ) )( a, b );  
  8.     private static readonly  
  9.         Func<Func<Func<T1, T2, TR>, Func<T1, T2, TR>>, Func<T1, T2, TR>>  
  10.             _fixPointGenerator =  
  11.                 _yCombinator( _yCombinator );  
  12.   
  13.     public static Func<Func<Func<T1, T2, TR>, Func<T1, T2, TR>>, Func<T1, T2, TR>> Fix {  
  14.         get { return _fixPointGenerator; }  
  15.     }  
  16. }  

可以看出這個(gè)Functional<T1,T2,TR>跟前面的Functional<T,TR>內容幾乎是一樣的(也就是Y組合子的實(shí)現而已,見(jiàn)過(guò)“(Y F) = (F (YF))”么?),只是參數的個(gè)數不一樣而已;很可惜這種變化很難進(jìn)一步封裝,只能用到多少個(gè)參數的時(shí)候就定義一個(gè)對應的泛型類(lèi)。

然后通過(guò)lambda表達式定義一個(gè)輔助用的委托:
C#代碼
  1. Func<Func<Action[ ], intobject>, Func<Action[ ], intobject>> invokeAll =  
  2.     invokeIter => ( actions, index ) =>  
  3.         index < actions.Length ?  
  4.         actions[ index ].DynamicInvoke( ) ?? invokeIter( actions, index + 1 ) :  
  5.         null;  


這樣我們就能把下面這個(gè)帶有語(yǔ)句塊的lambda表達式:
C#代碼
  1. int x, int y ) => {  
  2.     Console.WriteLine( "x = {0}", x );  
  3.     Console.WriteLine( "y = {0}", y );  
  4.     Console.WriteLine( "x+y = {0}", x + y );  
  5. }  

轉換成這樣:
C#代碼
  1. ( x, y ) =>  
  2.     Functional<Action[ ], intobject>.Fix( invokeAll )( new Action[ ] {  
  3.         ( ) => Console.WriteLine( "x = {0}", x ),  
  4.         ( ) => Console.WriteLine( "y = {0}", y ),  
  5.         ( ) => Console.WriteLine( "x+y = {0}", x + y )  
  6.     }, 0 )  

當然還有辦法進(jìn)一步抽象,不過(guò)這個(gè)樣子已經(jīng)比前面的版本要簡(jiǎn)潔了,不是么?
順帶一提,把那些輔助類(lèi)和委托的有效部分直接寫(xiě)在這個(gè)lambda表達式里也可以,不過(guò)這里為了代碼簡(jiǎn)潔還是分開(kāi)寫(xiě)了。如果把所有東西合在一起的話(huà)……(SelfApplicable的定義還是得在別處聲明)
C#代碼
  1. Expression<Action<intint>> expr = ( arg1, arg2 ) =>  
  2.     ( ( SelfApplicable<  
  3.             Func<  
  4.                 Func<  
  5.                     Func<Action[ ], intobject>,  
  6.                     Func<Action[ ], intobject>  
  7.                 >,  
  8.                 Func<Action[ ], intobject>>> ) (  
  9.         y => f => ( a, b ) => f( y( y )( f ) )( a, b ) )  
  10.     )( y => f => ( a, b ) => f( y( y )( f ) )( a, b )  
  11.     )( invokeIter => ( actions, index ) =>  
  12.         index < actions.Length ?  
  13.         actions[ index ].DynamicInvoke( ) ?? invokeIter( actions, index + 1 ) :  
  14.         null  
  15.     )( new Action[ ] {  
  16.         ( ) => Console.WriteLine( "x = {0}", arg1 ),  
  17.         ( ) => Console.WriteLine( "y = {0}", arg2 ),  
  18.         ( ) => Console.WriteLine( "x+y = {0}", arg1 + arg2 )  
  19.     }, 0 );  

(順便賦值給Expression<Action<int,int>>來(lái)讓編譯器生成Expression tree。很明顯把幾個(gè)lambda表達式合成一個(gè)之后,要顯式指定的類(lèi)型就沒(méi)那么多了,都集中在開(kāi)始的那個(gè)類(lèi)型轉換上。)
這樣調用就行:
C#代碼
  1. expr.Compile( )( 1, 2 );  
  2. // x = 1  
  3. // y = 2  
  4. // x+y = 3  


敬請期待后續文章。
Have fun with Expression trees!
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
C# Lambda表達式詳解,及Lambda表達式樹(shù)的創(chuàng )建
利用C#將Lambda表達式轉化成Expression樹(shù)
c#編程指南(二) LINQ表達式 (LINQ Expression)
由淺入深表達式樹(shù)(一)
打造自己的LINQ Provider(上):Expression Tree揭秘
C#-表達式樹(shù)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

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