1. 程式人生 > >.net 系列:Expression表達式樹、lambda、匿名委托 的使用

.net 系列:Expression表達式樹、lambda、匿名委托 的使用

exp 動態 hello pan cat lambda表達式 被調用 方法 語句

首先定義一個泛型委托類型,如下:

public delegate T Function<T>(T a, T b);

實現泛型委托的主體代碼,並調用:

 1 public static string Add(string a, string b)
 2           {
 3                 return string.Format("{0} #### {1}",a,b);
 4           }
 5  //實名委托方式
 6  Function<string> func = new Function<string>(Add);
7 Console.WriteLine( func("hello", "world") ); 8 9 //匿名委托方式 10 Function<string> func1 = new Function<string>(delegate(string a, string b) { 11 return string.Format("{0} @@@@ {1}",a,b); 12 }); 13 Console.WriteLine(func1("hello", "world")); 14 15 //Lambda表達式方式 16 Function<string
> func2 = (a, b) => string.Format("{0} **** {1}", a, b); 17 Console.WriteLine(func2("hello", "world")); 18 19 Expression<Function<string>> func2_0; 20 //func2_0 = func; //不支持將委托直接賦值給表達式樹 21 //func2_0 = func1; //不支持將委托直接賦值給表達式樹 22 //func2_0 = func2; //不支持將委托直接賦值給表達式樹 23 24 //(a, b) => string.Format("{0} **** {1}", a, b)語句塊的類型是lambda expression,即我們常說的lambda表達式
25 //所以,func2_0 = (a, b) => string.Format("{0} **** {1}", a, b)的直接賦值是沒有問題的。 26 func2_0 = (a, b) => string.Format("{0} **** {1}", a, b); 27 Console.WriteLine(func2_0.Compile()("hello", "world"));

以上代碼展示了委托類型Function<T>主體定義的四種方式,分別是實名委托、匿名委托、Lambda表達式、expression表達式樹。

從Function<T>委托主體的代碼定義來看是越來越簡單和友好,這些變化很大部分應歸功於C#的語法糖。

總結:不管委托主體在編寫的形式上怎麽簡化,但依然改變不了它委托類型的本質,當委托代碼塊被調用時會即時執行。

隨著C#的發展,後來加入了expression這個東東,簡稱表達式樹,我想用過ling to sql、linq to entity、linq to xml等等的你是不會陌生的。
expression是一種數據結構,我們可以將平常編寫的C#語句塊(或者叫表達式)的各部分進行分解並存入這個樹結構當中,保存在expression樹結構中的語句塊是不能直接執行的。
當我們需要將expression結構中的數據抽取並還原時就需要調用expression.Compile()方法,這裏我稱之為編譯。編譯後得到的結果就是我們之前存入的語句塊,這是數據結構還原成語句塊的過程(這是一個比喻)。
當然將數據還原成語句塊時依據解析引擎的不同會產生不同的輸出結果,如果引擎是linq to sql那麽解析後輸出的就是可供數據庫執行的sql,如果引擎是linq to xml則解析後輸出的是Xpath之類的表達式(沒親自驗證)

下面就請你和我一起來體驗一下expression表達式數據的存儲和編譯輸出吧!!!!仍以上面的場景為例子

 1 //expression表達式樹主體構造開始
 2 ParameterExpression paramA = Expression.Parameter(typeof(object), "a"); //聲明Lambda表達式中的參數表達式a
 3 ParameterExpression paramB = Expression.Parameter(typeof(object), "b"); //聲明Lambda表達式中的參數表達式b
 4 ConstantExpression constantExp = Expression.Constant("{0} !!!!! {1}",typeof(string));//聲明文本塊常量表達式
 5 MethodCallExpression bodyExp = Expression.Call(typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object), typeof(object) })
 6                 , new Expression[] { constantExp, paramA, paramB }); //聲明String.Format()方法調用表達式
 7 //expression表達式樹主體構造結束
 8 
 9 
10 //1.構造類型為LambdaExpression的lambda表達式樹,編譯後得到委托的基元類型(弱類型)。
11 LambdaExpression func3 = Expression.Lambda(bodyExp, paramA, paramB);//將以上各個表達式部分組合為Lambda表達式
12 Delegate dg = func3.Compile();//編譯表達式樹得到委托
13 Console.WriteLine(dg.DynamicInvoke("hello", "world"));//調用委托並將結果輸出到控制臺
14 //Console.WriteLine(func3.Compile().DynamicInvoke("hello", "world")); //上面兩步可以簡化為這句代碼
15 
16 //2.構造類型為Expression<Function<string>>的泛型lambda表達式樹,編譯後得到委托可直接調用。
17 Expression<Function<string>> func4 = Expression.Lambda<Function<string>>(bodyExp, paramA, paramB);
18 Console.WriteLine(func4.Compile()("xxxx", "yyyy"));
19 
20  //3.構造類型為Expression<Func<string, string, string>>的泛型lambda表達式樹,編譯後得到委托可直接調用。
21  //與上面的區別是這裏用系統定義的Func<in T1, in T2, out TResult>泛型委托代替了自定義的Function<T>委托。
22  Expression<Func<string, string, string>> func5 = Expression.Lambda<Func<string, string, string>>(bodyExp, paramA, paramB);
23  Console.WriteLine(func5.Compile()("yyyy", "zzzz"));
24 
25  //以上總結了expression表達式的創建和調用的不同方式,以下是幾個有關expression的擴展例子
26  //4.動態構造string.Concat("hello", "world")語句塊
27  var concatMethod = typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string) });
28  var addExpr = Expression.Add(Expression.Constant("hello "), Expression.Constant("world"), concatMethod);
29  Expression<Func<string>> e = Expression.Lambda<Func<string>>(addExpr);
30  Console.WriteLine(e.Compile()());
31 
32  //5.動態構造Math.Sin(100)語句塊
33  ParameterExpression expA = Expression.Parameter(typeof(double), "a"); //參數a
34  MethodCallExpression expCall = Expression.Call(
35         typeof(Math).GetMethod("Sin",new Type[]{typeof(double)}),expA); 
36  LambdaExpression exp = Expression.Lambda(expCall, expA); // a => Math.Sin(a)
37  Console.WriteLine( exp.Compile().DynamicInvoke(100) );
38 
39  //6.動態構造Console.WriteLine("aaa")語句塊
40  ConstantExpression _constExp = Expression.Constant("aaa", typeof(string));//一個常量
41  MethodCallExpression _methodCallexp = Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), _constExp);
42  Expression<Action> consoleLambdaExp = Expression.Lambda<Action>(_methodCallexp);
43  consoleLambdaExp.Compile()();

.net 系列:Expression表達式樹、lambda、匿名委托 的使用