淺談表達(dá)式樹和泛型委托
什么是表達(dá)式樹?
表達(dá)式樹又稱為表達(dá)式目錄樹,以數(shù)據(jù)形式表示語(yǔ)言級(jí)代碼。所有的數(shù)據(jù)都存儲(chǔ)在樹結(jié)構(gòu)中,每個(gè)結(jié)點(diǎn)表示一個(gè)表達(dá)式(Expression)。要想手動(dòng)生成表達(dá)式樹我們需要引用System.Linq.Expressions 命名空間,最重要的一個(gè)類是Expression,它是所有表達(dá)式的基類。例如:
1:參數(shù)表達(dá)式:ParameterExpression,就是一個(gè)方法中的參數(shù),例如 search(string key),key可以看成是一個(gè)參數(shù)表達(dá)式。
2:二元表達(dá)式:BinaryExpression,例如a+b等。
3:方法調(diào)用表達(dá)式:MethodCallExpression,例如:自定義LINQ提供程序中實(shí)現(xiàn)orderby 的操作:
MethodCallExpressionorderByCallExpression=Expression.Call( |
4:常數(shù)表達(dá)式:ConstantExpression,例如數(shù)值5。
5:字段或?qū)傩员磉_(dá)式:MemberExpression,例如str.Length。Expression.Property(pe, typeof(string).GetProperty("Length"));
6:帶有條件運(yùn)算的表達(dá)式:ConditionalExpression。
7:描述lambda表達(dá)式:LambdaExpression
8:一元運(yùn)算符的表達(dá)式:UnaryExpression
9:表達(dá)式和類型之間的相關(guān)操作:TypeBinaryExpression等等,它們都繼承Expression。
泛型委托:
表達(dá)式樹經(jīng)常與泛型委托一起使用,這里簡(jiǎn)單介紹下什么是泛型委托。Func<(Of <(T, TResult>)>) 泛型委托:封裝一個(gè)具有一個(gè)參數(shù)并返回 TResult 參數(shù)指定的類型值的方法。如果想增加參數(shù)可以寫成Func<(Of <(T1,T2, TResult>)>) 等。這種方法比起傳統(tǒng)的顯示聲明委托的方法從代碼結(jié)構(gòu)上要簡(jiǎn)化不少,我們不用特意去申請(qǐng)一個(gè)delegate,所有的委托都可以用泛型委托來(lái)代替。這里簡(jiǎn)單來(lái)實(shí)現(xiàn)一個(gè)算術(shù)表達(dá)式來(lái)說(shuō)明泛型委托的好處。
算術(shù)表達(dá):(a+b)^b
1:傳統(tǒng)的顯示申明委托方式。
1):申明一個(gè)委托:
/// |
2):編碼委托對(duì)應(yīng)的方法體
/// 3):調(diào)用: doubledResult=0; PowerComputepc=GetPowerCompute; dResult=pc(2,2); Console.WriteLine(dResult.ToString()); |
2:泛型委托實(shí)現(xiàn):
1):編碼委托對(duì)應(yīng)的方法體,方法同上面代碼中第二步。
2):調(diào)用
dResult=fc(2,2);
Console.WriteLine(dResult.ToString());
表達(dá)式樹的執(zhí)行:
表達(dá)式樹和泛型委托:這里實(shí)現(xiàn)一個(gè)簡(jiǎn)單的表達(dá)式樹,實(shí)現(xiàn)(a+b)^b, 過程中需要知道以下三個(gè)比較重要的方法。
1:Expression<(Of <(TDelegate>)>) :以表達(dá)式目錄樹的形式將強(qiáng)類型 lambda 表達(dá)式表示為數(shù)據(jù)結(jié)構(gòu)。
2: Expression.Lambda方法:創(chuàng)建一個(gè)表示 lambda 表達(dá)式的表達(dá)式目錄樹。
3:Expression<(Of <(TDelegate>)>).Compile :將表達(dá)式目錄樹描述的 lambda 表達(dá)式編譯為可執(zhí)行代碼。
下面是(a+b)^b的表達(dá)式樹生成可執(zhí)行代碼并且在客戶端進(jìn)行調(diào)用的代碼:
ParameterExpressionpenum_1=Expression.Parameter(typeof(double),"num_1"); Expression.Lambda |
下面是(a+b)^b的表達(dá)式樹的關(guān)系圖
表達(dá)式樹的修改:
表達(dá)式目錄樹是不可變的,這意味著不能直接修改表達(dá)式目錄樹。若要更改表達(dá)式目錄樹,必須創(chuàng)建現(xiàn)有表達(dá)式目錄樹的一個(gè)副本,并在創(chuàng)建副本的過程中執(zhí)行所需更改。您可以使用表達(dá)式目錄樹訪問器遍歷現(xiàn)有表達(dá)式目錄樹,并復(fù)制它訪問的每個(gè)節(jié)點(diǎn)。我們可以創(chuàng)建自定義類來(lái)繼承ExpressionVisitor,在自定義類中重定相應(yīng)方式來(lái)達(dá)到修改表達(dá)式樹的目的。
【編輯推薦】