当前位置: 移动技术网 > IT编程>开发语言>c# > C# 表达式树遍历(二)

C# 表达式树遍历(二)

2019年09月16日  | 移动技术网IT编程  | 我要评论

一、前言

我们对表达式树有了初步的认识,这里我们将对表达式树进行遍历,只有弄清楚了他的运行原理,我们才可以对他进行定制化修改。

表达式系列目录

c# 表达式树讲解(一)

c# 表达式树遍历(二)

 c# 表达式树分页扩展(三)

c# 表达式树lambda扩展(四)

二、表达式树的遍历

要查看表达式树的遍历,肯定不能直接用.net framework封装的方法,因为.net framework框架是闭源的,除了看中间语言(il)去查看。我们就用expressionvisitor类查看一下他的运行原理,看了下expressionvisitor类,里面都是对各个表达式的访问,而且都是虚拟函数,我们可以对他进行override。

expressionvisitor类里面都是对各个类型的表达式进行访问,为了更好的理解里面的访问顺序,蜗牛把里面的虚函数都override了一遍,然后跟踪里面的执行顺序。【傻眼了,35个虚函数需要override,内心是很拒绝的,vs2019有没有重写父类虚函数的快捷键啊!!!!!!!】

expressionvisitor类相关介绍:

2.1、expressionvisitor类的跟踪

为了不改变expressionvisitor类原来的访问,创建的snailexpressionvisitor.cs 文件只在重写方法里面添加日志打印。

代码如下:

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);
        }



    }

调用方法:

expression<func<int, int, bool>> fun = (x, y) => x - y > 5;

var treemodifier = new snailexpressionvisitor();
expression modifiedexpr = treemodifier.visit(fun);

运行结果:

从打印的日志里面可以看出,

1、每次访问表达式类时,都会先去调用visit函数,估计他是在visit里面判定表达式类,然后在根据表达式类的类型,调用访问改表达式的函数

2、对lambda表达式类,是先访问的是expression<t>。expression<t>是不是很熟悉,上一章说过他的作用是将强类型lambda表达式表示为表达式树形式的数据结构,解析成功之后才对表达式的访问

3、对于表达式先解析的是左边,左边的内容解析完了之后在解析右边,如(x-y)>5,解析的顺序是:x-y=>x=>y=>5

2.2、修改表达式树

既然我们弄清楚了表达式树的访问,现在我们就可以对他进行编辑修改了。

上面我们判断的是x-y>5,现在我们规定,将“-”改成“+”,“>”改成“>=”

对visitbinary方法修改代码如下:

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);
    }
}

调用方法:

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()}");

运行结果如下

三、总结

对表达树的讲解已经完成了,但是说了这么久,对真实的开发有什么作用呢?后面我将利用lambda表达式写一个对现有数据分页的公共方法,同时在对dapper的扩展也会用到相关知识点,大家拭目以待吧……

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网