一、前言
上一篇 <https://www.cnblogs.com/snailblog/p/11521043.html>
我們對(duì)表達(dá)式樹有了初步的認(rèn)識(shí),這里我們將對(duì)表達(dá)式樹進(jìn)行遍歷,只有弄清楚了他的運(yùn)行原理,我們才可以對(duì)他進(jìn)行定制化修改。
表達(dá)式系列目錄
C# 表達(dá)式樹講解(一) <https://www.cnblogs.com/snailblog/p/11521043.html>
C# 表達(dá)式樹遍歷(二)
?C# 表達(dá)式樹分頁(yè)擴(kuò)展(三) <https://www.cnblogs.com/snailblog/p/11521359.html>
C# 表達(dá)式樹Lambda擴(kuò)展(四) <https://www.cnblogs.com/snailblog/p/11525118.html>
二、表達(dá)式樹的遍歷
要查看表達(dá)式樹的遍歷,肯定不能直接用.Net Framework封裝的方法,因?yàn)?Net
Framework框架是閉源的,除了看中間語(yǔ)言(IL)去查看。我們就用ExpressionVisitor類查看一下他的運(yùn)行原理,看了下ExpressionVisitor類,里面都是對(duì)各個(gè)表達(dá)式的訪問,而且都是虛擬函數(shù),我們可以對(duì)他進(jìn)行override。
ExpressionVisitor類里面都是對(duì)各個(gè)類型的表達(dá)式進(jìn)行訪問,為了更好的理解里面的訪問順序,蝸牛把里面的虛函數(shù)都o(jì)verride了一遍,然后跟蹤里面的執(zhí)行順序。【傻眼了,35個(gè)虛函數(shù)需要override,內(nèi)心是很拒絕的,vs2019有沒有重寫父類虛函數(shù)的快捷鍵?。。。。。。?!】
ExpressionVisitor類相關(guān)介紹:
https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.expressionvisitor?view=netframework-4.8
<https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.expressionvisitor?view=netframework-4.8>
2.1、ExpressionVisitor類的跟蹤
為了不改變ExpressionVisitor類原來(lái)的訪問,創(chuàng)建的SnailExpressionVisitor.cs 文件只在重寫方法里面添加日志打印。
代碼如下:
public class SnailExpressionVisitor : ExpressionVisitor { public override
Expression Visit(Expression node) { Console.WriteLine($"訪問了
Visit,內(nèi)容:{node.ToString()}"); return base.Visit(node); } protected override
CatchBlock VisitCatchBlock(CatchBlock node) { Console.WriteLine($"訪問了
VisitCatchBlock,內(nèi)容:{node.ToString()}"); return base.VisitCatchBlock(node); }
protected override ElementInit VisitElementInit(ElementInit node) {
Console.WriteLine($"訪問了 VisitElementInit,內(nèi)容:{node.ToString()}"); return base
.VisitElementInit(node); }protected override LabelTarget
VisitLabelTarget(LabelTarget node) { Console.WriteLine($"訪問了
VisitLabelTarget,內(nèi)容:{node.ToString()}"); return base.VisitLabelTarget(node); }
protected override MemberAssignment VisitMemberAssignment(MemberAssignment
node) { Console.WriteLine($"訪問了 VisitMemberAssignment,內(nèi)容:{node.ToString()}");
return base.VisitMemberAssignment(node); } protected override MemberBinding
VisitMemberBinding(MemberBinding node) { Console.WriteLine($"訪問了
VisitMemberBinding,內(nèi)容:{node.ToString()}"); return base
.VisitMemberBinding(node); }protected override MemberListBinding
VisitMemberListBinding(MemberListBinding node) { Console.WriteLine($"訪問了
VisitMemberListBinding,內(nèi)容:{node.ToString()}"); return base
.VisitMemberListBinding(node); }protected override MemberMemberBinding
VisitMemberMemberBinding(MemberMemberBinding node) { Console.WriteLine($"訪問了
VisitMemberMemberBinding,內(nèi)容:{node.ToString()}"); return base
.VisitMemberMemberBinding(node); }protected override SwitchCase
VisitSwitchCase(SwitchCase node) { Console.WriteLine($"訪問了
VisitSwitchCase,內(nèi)容:{node.ToString()}"); return base.VisitSwitchCase(node); }
protected override Expression VisitBinary(BinaryExpression node) {
Console.WriteLine($"訪問了 VisitBinary,內(nèi)容:{node.ToString()}"); return base
.VisitBinary(node); }protected override Expression VisitBlock(BlockExpression
node) { Console.WriteLine($"訪問了 VisitBlock,內(nèi)容:{node.ToString()}"); return base
.VisitBlock(node); }protected override Expression
VisitConditional(ConditionalExpression node) { Console.WriteLine($"訪問了
VisitConditional,內(nèi)容:{node.ToString()}"); return base.VisitConditional(node); }
protected override Expression VisitConstant(ConstantExpression node) {
Console.WriteLine($"訪問了 VisitConstant,內(nèi)容:{node.ToString()}"); return base
.VisitConstant(node); }protected override Expression
VisitDebugInfo(DebugInfoExpression node) { Console.WriteLine($"訪問了
VisitDebugInfo,內(nèi)容:{node.ToString()}"); return base.VisitDebugInfo(node); }
protected override Expression VisitDefault(DefaultExpression node) {
Console.WriteLine($"訪問了 VisitDefault,內(nèi)容:{node.ToString()}"); return base
.VisitDefault(node); }protected override Expression
VisitDynamic(DynamicExpression node) { Console.WriteLine($"訪問了
VisitDynamic,內(nèi)容:{node.ToString()}"); return base.VisitDynamic(node); } protected
override Expression VisitExtension(Expression node) { Console.WriteLine($"訪問了
VisitExtension,內(nèi)容:{node.ToString()}"); return base.VisitExtension(node); }
protected override Expression VisitGoto(GotoExpression node) {
Console.WriteLine($"訪問了 VisitGoto,內(nèi)容:{node.ToString()}"); return base
.VisitGoto(node); }protected override Expression VisitIndex(IndexExpression
node) { Console.WriteLine($"訪問了 VisitIndex,內(nèi)容:{node.ToString()}"); return base
.VisitIndex(node); }protected override Expression
VisitInvocation(InvocationExpression node) { Console.WriteLine($"訪問了
VisitInvocation,內(nèi)容:{node.ToString()}"); return base.VisitInvocation(node); }
protected override Expression VisitLabel(LabelExpression node) {
Console.WriteLine($"訪問了 VisitLabel,內(nèi)容:{node.ToString()}"); return base
.VisitLabel(node); }protected override Expression VisitLambda<T>(Expression<T>
node) { Console.WriteLine($"訪問了 VisitLambda,內(nèi)容:{node.ToString()}"); return base
.VisitLambda(node); }protected override Expression
VisitListInit(ListInitExpression node) { Console.WriteLine($"訪問了
VisitListInit,內(nèi)容:{node.ToString()}"); return base.VisitListInit(node); }
protected override Expression VisitLoop(LoopExpression node) {
Console.WriteLine($"訪問了 VisitLoop,內(nèi)容:{node.ToString()}"); return base
.VisitLoop(node); }protected override Expression VisitMember(MemberExpression
node) { Console.WriteLine($"訪問了 VisitMember,內(nèi)容:{node.ToString()}"); return base
.VisitMember(node); }protected override Expression
VisitMemberInit(MemberInitExpression node) { Console.WriteLine($"訪問了
VisitMemberInit,內(nèi)容:{node.ToString()}"); return base.VisitMemberInit(node); }
protected override Expression VisitMethodCall(MethodCallExpression node) {
Console.WriteLine($"訪問了 VisitMethodCall,內(nèi)容:{node.ToString()}"); return base
.VisitMethodCall(node); }protected override Expression VisitNew(NewExpression
node) { Console.WriteLine($"訪問了 VisitNew,內(nèi)容:{node.ToString()}"); return base
.VisitNew(node); }protected override Expression
VisitNewArray(NewArrayExpression node) { Console.WriteLine($"訪問了
VisitNewArray,內(nèi)容:{node.ToString()}"); return base.VisitNewArray(node); }
protected override Expression VisitParameter(ParameterExpression node) {
Console.WriteLine($"訪問了 VisitParameter,內(nèi)容:{node.ToString()}"); return base
.VisitParameter(node); }protected override Expression
VisitRuntimeVariables(RuntimeVariablesExpression node) { Console.WriteLine($"
訪問了 VisitRuntimeVariables,內(nèi)容:{node.ToString()}"); return base
.VisitRuntimeVariables(node); }protected override Expression
VisitSwitch(SwitchExpression node) { Console.WriteLine($"訪問了
VisitSwitch,內(nèi)容:{node.ToString()}"); return base.VisitSwitch(node); } protected
override Expression VisitTry(TryExpression node) { Console.WriteLine($"訪問了
VisitTry,內(nèi)容:{node.ToString()}"); return base.VisitTry(node); } protected
override Expression VisitTypeBinary(TypeBinaryExpression node) {
Console.WriteLine($"訪問了 VisitTypeBinary,內(nèi)容:{node.ToString()}"); return base
.VisitTypeBinary(node); }protected override Expression
VisitUnary(UnaryExpression node) { Console.WriteLine($"訪問了
VisitUnary,內(nèi)容:{node.ToString()}"); return base.VisitUnary(node); } }
調(diào)用方法:
Expression<Func<int, int, bool>> fun = (x, y) => x - y > 5; var treeModifier =
new SnailExpressionVisitor(); Expression modifiedExpr = treeModifier.Visit(fun);
運(yùn)行結(jié)果:
<https://img2018.cnblogs.com/blog/1764554/201909/1764554-20190915102305051-1533802902.png>
從打印的日志里面可以看出,
1、每次訪問表達(dá)式類時(shí),都會(huì)先去調(diào)用Visit函數(shù),估計(jì)他是在Visit里面判定表達(dá)式類,然后在根據(jù)表達(dá)式類的類型,調(diào)用訪問改表達(dá)式的函數(shù)
2、對(duì)Lambda表達(dá)式類,是先訪問的是Expression<T>。Expression<T>是不是很熟悉,上一章說(shuō)過(guò)他的作用是將強(qiáng)類型Lambda表達(dá)式表示為表達(dá)式樹形式的數(shù)據(jù)結(jié)構(gòu),解析成功之后才對(duì)表達(dá)式的訪問
3、對(duì)于表達(dá)式先解析的是左邊,左邊的內(nèi)容解析完了之后在解析右邊,如(x-y)>5,解析的順序是:x-y=>x=>y=>5
2.2、修改表達(dá)式樹
既然我們弄清楚了表達(dá)式樹的訪問,現(xiàn)在我們就可以對(duì)他進(jìn)行編輯修改了。
上面我們判斷的是x-y>5,現(xiàn)在我們規(guī)定,將“-”改成“+”,“>”改成“>=”
對(duì)VisitBinary方法修改代碼如下:
protected override Expression VisitBinary(BinaryExpression node) {
Console.WriteLine($"訪問了 VisitBinary,內(nèi)容:{node.ToString()}"); if (node.NodeType
== ExpressionType.GreaterThan) { Expression left =this.Visit(node.Left);
Expression right =this.Visit(node.Right); var result =
Expression.MakeBinary(ExpressionType.GreaterThanOrEqual, left, right,
node.IsLiftedToNull, node.Method); Console.WriteLine($"訪問了
VisitBinary,更改之后的內(nèi)容:{result.ToString()}"); return result; } else if
(node.NodeType == ExpressionType.Subtract || node.NodeType ==
ExpressionType.SubtractChecked) { Expression left =this.Visit(node.Left);
Expression right =this.Visit(node.Right); var result =
Expression.MakeBinary(ExpressionType.Add, left, right, node.IsLiftedToNull,
node.Method); Console.WriteLine($"訪問了 VisitBinary,更改之后的內(nèi)容:{result.ToString()}");
return result; } else { return base.VisitBinary(node); } }
調(diào)用方法:
Expression<Func<int, int, bool>> fun = (x, y) => x - y > 5; var treeModifier =
new SnailExpressionVisitor(); Expression modifiedExpr =
treeModifier.Visit(fun); Console.WriteLine($"
Lambda的轉(zhuǎn)換最后結(jié)果:{modifiedExpr.ToString()}");
運(yùn)行結(jié)果如下
<https://img2018.cnblogs.com/blog/1764554/201909/1764554-20190915102306070-1298442000.png>
三、總結(jié)
對(duì)表達(dá)樹的講解已經(jīng)完成了,但是說(shuō)了這么久,對(duì)真實(shí)的開發(fā)有什么作用呢?后面我將利用Lambda表達(dá)式寫一個(gè)對(duì)現(xiàn)有數(shù)據(jù)分頁(yè)的公共方法,同時(shí)在對(duì)Dapper的擴(kuò)展也會(huì)用到相關(guān)知識(shí)點(diǎn),大家拭目以待吧……
熱門工具 換一換