• 使用ExpressionVisitor进行lambadaExpression的动态拼接


    现有如下实体

        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }

    根据这个实体创建一个Iqueryable<User>对象queryList

    List<User> dList = new List<User> {
                    new User{Id=1,Name="zhansan" },
                    new User{Id=2,Name="lisi" },
                    new User{Id=3,Name="wangwu" },
                    new User{Id=4,Name="zhaoliu" },
                    new User{Id=5,Name="sunqi" },
                };
    

    dList的where方法需要一个Func<User, bool> whereFunc参数来进行数据过滤,但很多时候whereFunc是动态的,我的查询条件有时是u=>u.Id==1||u.Id==2,有时条件为u=>u.Id==1||u.Id==2&&u.Name=="lisi"

    如此看来条件是不固定的并且属性组合方式多种多样,这样就迫切地需要一种方法可以动态地拼接表达式

    如下两个表达式,将演示如何和为一个表达式

    Expression<Func<User, bool>> ef = u => u.Id == 1 || u.Id == 2;
    Expression<Func<User, bool>> ef2 = y => y.Name == "lisi";

    首先创建类MyVisitor

        public class MyVisitor : ExpressionVisitor
        {
            Dictionary<ParameterExpression, ParameterExpression> map;
            public MyVisitor(Dictionary<ParameterExpression, ParameterExpression> map)
            {
                this.map = map;
            }
            protected override Expression VisitParameter(ParameterExpression node)
            {
                return map[node];
            }
        }

    此类继承自ExpressionVisitor类,此类是expression表达式的工具类,可对expression表达式内部的成员进行替换

    首先我自定义了构造函数传入一个字典对象。作用在后面解释

    然后我重写了VisitorParameter方法,此方法的参数node即为要修改的expression的参数部分,你的expression有多少个参数就会顺序触发此方法并传入相应参数

    准备工作到此就结束了,接下来是拼接过程

    var pl = ef.Parameters;
    var dic = ef.Parameters.Select((f, i) => new { f, f2 = ef2.Parameters[i] }).ToDictionary(p => p.f2, p => p.f);
    MyVisitor myVisitor = new MyVisitor(dic);
    var body = myVisitor.Visit(ef2.Body);
    var finalBody = Expression.And(ef.Body, body);
    var fu = Expression.Lambda<Func<User, bool>>(finalBody, pl).Compile();
    var re= dList.Where(fu).ToList();

    首先得到字典dic其key为ef2的参数列表,值为ef的参数列表

    然后创建刚才自定义的MyVisitor类的对象,并传入字典dic

    之后调用myVisitor的Visit方法传入ef2的Body部分,此时根据MyVisitor中对VisitParameter的重写可知

    protected override Expression VisitParameter(ParameterExpression node)
    {
         return map[node];
    }

    在内部myVisitor对传入的ef2.Body的每一个参数查询字典,并返回值,此值即为ef的参数值,此处就将ef2的参数都替换为ef1的参数了

    接下来就是两个表达式的拼接部分

    var body = myVisitor.Visit(ef2.Body);
    var finalBody = Expression.And(ef.Body, body);
    var fu = Expression.Lambda<Func<User, bool>>(finalBody, pl).Compile();

    将两个表达式的body部分用and连接,并且使用pl为参数(这很重要,前面做这么多就是为了把ef2的body部分的参数更换为ef的参数)

     这样就得到了拼接后的func,传入where作为条件进行查询

    var re= dList.Where(fu).ToList();
    

      

  • 相关阅读:
    python实现对单机游戏内存修改
    python_turtle模板画图
    Android向Rest服务Post数据遇到的Date类型数据问题
    Jquery根据字段内容设置字段宽度
    LLVM安装
    impala编译
    JS一些简单的问题
    小三角形的制作方法
    js中的一些简单问题
    另一部分页面
  • 原文地址:https://www.cnblogs.com/huanent/p/5575633.html
Copyright © 2020-2023  润新知