ibcadmin 发表于 2019-9-17 11:29:35

C# 表达式树遍历

<h2>一、媒介</h2>
<p>上一篇我们对表达式树有了开端的认识,这里我们将对表达式树举行遍历,只有弄清楚了他的运行原理,我们才可以对他举行定制化修改。</p>
<p>表达式系列目录</p>
<p>C# 表达式树解说(一)</p>
<p>C# 表达式树遍历(二)</p>
<p> C# 表达式树分页扩展(三)</p>
<h2>二、表达式树的遍历</h2>
<p>要检察表达式树的遍历,肯定不能直接用.Net Framework封装的方法,因为.Net Framework框架是闭源的,除了看中间语言(IL)去检察。我们就用ExpressionVisitor类检察一下他的运行原理,看了下ExpressionVisitor类,里面都是对各个表达式的访问,而且都是虚拟函数,我们可以对他举行override。</p>
<p>ExpressionVisitor类里面都是对各个范例的表达式举行访问,为了更好的明白里面的访问次序,蜗牛把里面的虚函数都override了一遍,然后跟踪里面的实行次序。【傻眼了,35个虚函数必要override,内心是很拒绝的,vs2019有没有重写父类虚函数的快捷键啊!!!!!!!】</p>
<p>ExpressionVisitor类相干先容:https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.expressionvisitor?view=netframework-4.8</p>
<h3>2.1、ExpressionVisitor类的跟踪</h3>
<p>为了不改变ExpressionVisitor类原来的访问,创建的SnailExpressionVisitor.cs 文件只在重写方法里面添加日记打印。</p>
<p>代码如下:</p>

public class SnailExpressionVisitor : ExpressionVisitor
    {
      public override Expression Visit(Expression node)
      {
            Console.WriteLine($"访问了 Visit,内容:{node.ToString()}");
            return base.Visit(node);
      }

      protected override CatchBlock VisitCatchBlock(CatchBlock node)
      {

            Console.WriteLine($"访问了 VisitCatchBlock,内容:{node.ToString()}");
            return base.VisitCatchBlock(node);
      }

      protected override ElementInit VisitElementInit(ElementInit node)
      {
            Console.WriteLine($"访问了 VisitElementInit,内容:{node.ToString()}");
            return base.VisitElementInit(node);
      }
      protected override LabelTarget VisitLabelTarget(LabelTarget node)
      {

            Console.WriteLine($"访问了 VisitLabelTarget,内容:{node.ToString()}");
            return base.VisitLabelTarget(node);
      }
      protected override MemberAssignment VisitMemberAssignment(MemberAssignment node)
      {

            Console.WriteLine($"访问了 VisitMemberAssignment,内容:{node.ToString()}");
            return base.VisitMemberAssignment(node);
      }
      protected override MemberBinding VisitMemberBinding(MemberBinding node)
      {

            Console.WriteLine($"访问了 VisitMemberBinding,内容:{node.ToString()}");
            return base.VisitMemberBinding(node);
      }

      protected override MemberListBinding VisitMemberListBinding(MemberListBinding node)
      {

            Console.WriteLine($"访问了 VisitMemberListBinding,内容:{node.ToString()}");
            return base.VisitMemberListBinding(node);
      }
      protected override MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding node)
      {

            Console.WriteLine($"访问了 VisitMemberMemberBinding,内容:{node.ToString()}");
            return base.VisitMemberMemberBinding(node);
      }
      protected override SwitchCase VisitSwitchCase(SwitchCase node)
      {
            Console.WriteLine($"访问了 VisitSwitchCase,内容:{node.ToString()}");
            return base.VisitSwitchCase(node);
      }
      protected override Expression VisitBinary(BinaryExpression node)
      {
            Console.WriteLine($"访问了 VisitBinary,内容:{node.ToString()}");
            return base.VisitBinary(node);
      }
      protected override Expression VisitBlock(BlockExpression node)
      {
            Console.WriteLine($"访问了 VisitBlock,内容:{node.ToString()}");
            return base.VisitBlock(node);
      }

      protected override Expression VisitConditional(ConditionalExpression node)
      {
            Console.WriteLine($"访问了 VisitConditional,内容:{node.ToString()}");
            return base.VisitConditional(node);
      }

      protected override Expression VisitConstant(ConstantExpression node)
      {
            Console.WriteLine($"访问了 VisitConstant,内容:{node.ToString()}");
            return base.VisitConstant(node);
      }
      protected override Expression VisitDebugInfo(DebugInfoExpression node)
      {
            Console.WriteLine($"访问了 VisitDebugInfo,内容:{node.ToString()}");
            return base.VisitDebugInfo(node);
      }
      protected override Expression VisitDefault(DefaultExpression node)
      {
            Console.WriteLine($"访问了 VisitDefault,内容:{node.ToString()}");
            return base.VisitDefault(node);
      }

      protected override Expression VisitDynamic(DynamicExpression node)
      {
            Console.WriteLine($"访问了 VisitDynamic,内容:{node.ToString()}");
            return base.VisitDynamic(node);
      }
      protected override Expression VisitExtension(Expression node)
      {
            Console.WriteLine($"访问了 VisitExtension,内容:{node.ToString()}");
            return base.VisitExtension(node);
      }
      protected override Expression VisitGoto(GotoExpression node)
      {
            Console.WriteLine($"访问了 VisitGoto,内容:{node.ToString()}");
            return base.VisitGoto(node);
      }
      protected override Expression VisitIndex(IndexExpression node)
      {
            Console.WriteLine($"访问了 VisitIndex,内容:{node.ToString()}");
            return base.VisitIndex(node);
      }
      protected override Expression VisitInvocation(InvocationExpression node)
      {
            Console.WriteLine($"访问了 VisitInvocation,内容:{node.ToString()}");
            return base.VisitInvocation(node);
      }
      protected override Expression VisitLabel(LabelExpression node)
      {
            Console.WriteLine($"访问了 VisitLabel,内容:{node.ToString()}");
            return base.VisitLabel(node);
      }
      protected override Expression VisitLambda<T>(Expression<T> node)
      {
            Console.WriteLine($"访问了 VisitLambda,内容:{node.ToString()}");
            return base.VisitLambda(node);
      }

      protected override Expression VisitListInit(ListInitExpression node)
      {
            Console.WriteLine($"访问了 VisitListInit,内容:{node.ToString()}");
            return base.VisitListInit(node);
      }
      protected override Expression VisitLoop(LoopExpression node)
      {
            Console.WriteLine($"访问了 VisitLoop,内容:{node.ToString()}");
            return base.VisitLoop(node);
      }
      protected override Expression VisitMember(MemberExpression node)
      {
            Console.WriteLine($"访问了 VisitMember,内容:{node.ToString()}");
            return base.VisitMember(node);
      }
      protected override Expression VisitMemberInit(MemberInitExpression node)
      {
            Console.WriteLine($"访问了 VisitMemberInit,内容:{node.ToString()}");
            return base.VisitMemberInit(node);
      }
      protected override Expression VisitMethodCall(MethodCallExpression node)
      {
            Console.WriteLine($"访问了 VisitMethodCall,内容:{node.ToString()}");
            return base.VisitMethodCall(node);
      }
      protected override Expression VisitNew(NewExpression node)
      {
            Console.WriteLine($"访问了 VisitNew,内容:{node.ToString()}");
            return base.VisitNew(node);
      }
      protected override Expression VisitNewArray(NewArrayExpression node)
      {
            Console.WriteLine($"访问了 VisitNewArray,内容:{node.ToString()}");
            return base.VisitNewArray(node);
      }

      protected override Expression VisitParameter(ParameterExpression node)
      {
            Console.WriteLine($"访问了 VisitParameter,内容:{node.ToString()}");
            return base.VisitParameter(node);
      }
      protected override Expression VisitRuntimeVariables(RuntimeVariablesExpression node)
      {
            Console.WriteLine($"访问了 VisitRuntimeVariables,内容:{node.ToString()}");
            return base.VisitRuntimeVariables(node);
      }

      protected override Expression VisitSwitch(SwitchExpression node)
      {
            Console.WriteLine($"访问了 VisitSwitch,内容:{node.ToString()}");
            return base.VisitSwitch(node);
      }
      protected override Expression VisitTry(TryExpression node)
      {
            Console.WriteLine($"访问了 VisitTry,内容:{node.ToString()}");
            return base.VisitTry(node);
      }

      protected override Expression VisitTypeBinary(TypeBinaryExpression node)
      {
            Console.WriteLine($"访问了 VisitTypeBinary,内容:{node.ToString()}");
            return base.VisitTypeBinary(node);
      }
      protected override Expression VisitUnary(UnaryExpression node)
      {
            Console.WriteLine($"访问了 VisitUnary,内容:{node.ToString()}");
            return base.VisitUnary(node);
      }



    }

<p>调用方法:</p>

Expression<Func<int, int, bool>> fun = (x, y) => x - y > 5;

var treeModifier = new SnailExpressionVisitor();
Expression modifiedExpr = treeModifier.Visit(fun);


<p>运行结果:</p>
<p><div align="center"></div></p>
<p>从打印的日记里面可以看出,</p>
<p>1、每次访问表达式类时,都会先去调用Visit函数,估计他是在Visit里面判定表达式类,然后在根据表达式类的范例,调用访问改表达式的函数</p>
<p>2、对Lambda表达式类,是先访问的是Expression<T>。Expression<T>是不是很熟悉,上一章说过他的作用是将强范例Lambda表达式表示为表达式树情势的数据结构,剖析成功之后才对表达式的访问</p>
<p>3、对于表达式先剖析的是左边,左边的内容剖析完了之后在剖析右边,如(x-y)>5,剖析的次序是:x-y=>x=>y=>5</p>
<h3>2.2、修改表达式树</h3>
<p>既然我们弄清楚了表达式树的访问,如今我们就可以对他举行编辑修改了。</p>
<p>上面我们判断的是x-y>5,如今我们规定,将“-”改成“+”,“>”改成“>=”</p>
<p>对VisitBinary方法修改代码如下:</p>

protected override Expression VisitBinary(BinaryExpression node)
{
    Console.WriteLine($"访问了 VisitBinary,内容:{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,更改之后的内容:{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,更改之后的内容:{result.ToString()}");
      return result;
    }
    else
    {
      return base.VisitBinary(node);
    }
}


<p>调用方法:</p>

Expression<Func<int, int, bool>> fun = (x, y) => x - y > 5;

var treeModifier = new SnailExpressionVisitor();
Expression modifiedExpr = treeModifier.Visit(fun);

Console.WriteLine($"Lambda的转换末了结果:{modifiedExpr.ToString()}");


<p>运行结果如下</p>
<p><div align="center"></div></p>
<h2>三、总结</h2>
<p>对表达树的解说已经完成了,但是说了这么久,对真实的开发有什么作用呢?反面我将使用Lambda表达式写一个对现有数据分页的公共方法,同时在对Dapper的扩展也会用到相干知识点,各人拭目以待吧……</p><br><br/><br/><br/><br/><br/>来源:<a href="https://www.cnblogs.com/snailblog/archive/2019/09/15/11521335.html" target="_blank">https://www.cnblogs.com/snailblog/archive/2019/09/15/11521335.html</a>
页: [1]
查看完整版本: C# 表达式树遍历