C#表達式樹的基本用法講解
表達式樹使用一種類似樹的結構來表示代碼,它的每個節(jié)點都是一個表達式,比如方法調用和x<y這樣的二元運算等。我們可以對表達式樹的內容進行編輯和運算,這樣能夠動態(tài)修改可執(zhí)行代碼,以及動態(tài)創(chuàng)建查詢等。我們可以使用匿名lambda表達式或者C# API來創(chuàng)建表達式樹。
這一系列文章,主要是對C#表達式樹的一種總結,基本知識參考MSDN的內容 這部分內容可以直接到MSDN上查看,后面的幾篇文章主要分享一下,在工作中碰到的應用到表達式樹的部分,謹做為記錄和分享。
生成表達式樹
通過lambda表達式創(chuàng)建表達式樹
可以通過將lambda表達式賦值給Expression<TDelegate>類型的變量,編譯器可以自動生成創(chuàng)建該lambda表達式的表達式樹。C#編譯器只能從lambda表達式生成表達式樹,只能是單行l(wèi)ambda表達式,不能解析多行l(wèi)ambda語句,如下,可以通過一下方式創(chuàng)建lambda表達式 num=>num<5的表達式樹:
Expression<Func<int, bool>> lambda = num => num < 5;
通過API創(chuàng)建表達式樹
使用API創(chuàng)建表達式,需要使用Expression類,這個類包含了創(chuàng)建特定類型表達式樹節(jié)點的靜態(tài)工廠方法,比如表示參數(shù)的變量ParameterExpression,表示方法調用的MethodExpression。ParameterExpression,MethodExpression以及其他特定的表達式類型都在System.Linq.Expression命名空間里定義,這些類型都派生于Expression抽象類。
下面的例子是使用API方式創(chuàng)建num=>num<5的lambda表達式對應的表達式樹:
ParameterExpression numPara = Expression.Parameter(typeof(int), "num");//參數(shù)num ConstantExpression five = Expression.Constant(5, typeof(int));//常數(shù)5 BinaryExpression numLessThanFive = Expression.LessThan(numPara, five); Expression<Func<int, bool>> lambda1 = Expression.Lambda<Func<int, bool>>(numLessThanFive, new ParameterExpression[] { numPara });
從.NET Framework 4開始,表達式樹API還支持賦值以及流程控制,比如循環(huán),條件塊和try ... catch塊等。相對于通過lambda表達式創(chuàng)建表達式樹,可以利用API創(chuàng)建更加復雜的表達式樹,比如下面使用API創(chuàng)建數(shù)字階乘的表達式樹:
//參數(shù)value ParameterExpression value = Expression.Parameter(typeof(int), "value"); //本地變量 ParameterExpression result = Expression.Parameter(typeof(int), "result"); //標簽,用來跳出循環(huán) LabelTarget label = Expression.Label(typeof(int)); //創(chuàng)建表達式塊 BlockExpression block = Expression.Block( //添加本地參數(shù)result new[] { result }, //result=1 賦值 Expression.Assign(result, Expression.Constant(1)), //循環(huán) Expression.Loop( //循環(huán)條件 Expression.IfThenElse( //如果 value>1 Expression.GreaterThan(value, Expression.Constant(1)), //則 result*=value--; Expression.MultiplyAssign(result, Expression.PostDecrementAssign(value)), //否則跳出loop循環(huán)。跳到label的語句執(zhí)行 Expression.Break(label, result) ), label ) ); //編譯表達式樹 Func<int, int> factor = Expression.Lambda<Func<int, int>>(block, value).Compile(); //執(zhí)行,輸出結果120 Console.WriteLine(factor(5));
解析表達式樹
在獲取了表達式樹之后,如何獲取表達式樹的每一個部分,這個在有些情況下非常有用,下面這個例子展示了如何獲取num=>num<5的各個部分。
Expression<Func<int, bool>> expreTree = num => num < 5; ParameterExpression param = (ParameterExpression)expreTree.Parameters[0];//num BinaryExpression operation = (BinaryExpression)expreTree.Body;//< ParameterExpression left = (ParameterExpression)operation.Left;//num ConstantExpression right = (ConstantExpression)operation.Right;//5 //output Decomposed expression: num => num LessThan 5 Console.WriteLine("Decomposed expression:{0} = > {1} {2} {3}", param.Name, left.Name, operation.NodeType, right.Value);
編譯表達式樹
Expression<TDelegate>類型有Compile方法,可以將表達式樹編譯成對應的TDelegate委托類型,使用方法如下:
// 創(chuàng)建表達式樹 Expression<Func<int, bool>> expr = num => num < 5; // 將表達式樹編譯成對應委托 Func<int, bool> result = expr.Compile(); //調用委托方法,輸出True Console.WriteLine(result(4)); //也可以直接編譯后調用,輸出True Console.WriteLine(expr.Compile()(4));
再比如,下面例子演示了,創(chuàng)建一個表達式樹,然后編譯執(zhí)行:
//創(chuàng)建表達式樹的執(zhí)行邏輯 BinaryExpression be = Expression.Power(Expression.Constant(2D), Expression.Constant(3D)); //創(chuàng)建表達式樹 Expression<Func<double>> le = Expression.Lambda<Func<double>>(be); //編譯表達式樹 Func<double> compileExpression = le.Compile(); //執(zhí)行l(wèi)ambda表達式,獲得結果8 double result = compileExpression(); Console.WriteLine(result);
表達式樹的修改
表達式樹是不可變對象(immutable),跟string類似,不能直接修改,只能復制一個然后重新構造。具體參考MSDN How to modify expression trees (C#).
結語
本篇全部內容參考MSDN上表達式樹部分的內容,如果有基礎建議直接看,這里只是個人作為筆記,也是表達式樹的最基礎部分,后文會介紹表達式樹的一些用法。
以上就是C#表達式樹的基本用法講解的詳細內容,更多關于C#表達式樹的資料請關注腳本之家其它相關文章!
相關文章
C#基礎:Dispose()、Close()、Finalize()的區(qū)別詳解
本篇文章是對c#中的Dispose()、Close()、Finalize()的區(qū)別進行了詳細的分析介紹,需要的朋友參考下2013-05-05C#中Convert.ToString和ToString的區(qū)別分析
這篇文章主要介紹了C#中Convert.ToString和ToString的區(qū)別,是C#初學者需要牢固掌握的技巧,需要的朋友可以參考下2014-08-08