• 表达式树动态拼接lambda


    动态拼接lambda表达式树

     

    前言

      最近在优化同事写的代码(我们的框架用的是dapperLambda),其中有一个这样很普通的场景——界面上提供了一些查询条件框供用户来进行过滤数据。由于dapperLambda按条件查询时是传入表达式树的参数,这样比如其中查询条件有一个是审核状态,另外五个是模糊查询,那这查询时的表达式树参数就要写两次,这样使得代码看起来有很多是重复的,而且如果查询条件多的情况下,在写那表达式树参数时也容易漏写或错写。所以我在想如果可以动态拼接这表达式树,那这代码就要精简很多了。

     正文

      也许我的上面文字描述让你不明觉里,那下面我就配以简单的代码来再说明一下这个问题:

    复制代码
    1 Expression<Func<SysUser, bool>> exp1 = s => s.UserName.Contains("1") && s.Age > 10;
    2 Expression<Func<SysUser, bool>> exp2 = s => s.UserName.Contains("1") && s.Age > 10 && s.IsEnable == 1;
    3 using (var context = new DbContext().ConnectionString(connString))
    4 {
    5     var result1 = context.Select<SysUser>(exp1).QueryMany();
    6     var result2 = context.Select<SysUser>(exp2).QueryMany();
    7 }
    复制代码

      上面代码两次查询,第一次查询结果result1的结果是用户名中包含1而且年龄大于10,而结果result2中就是在查询结果result1的条件上再加上帐号生效这一条件。所以我们看到exp1和exp2的表达式树绝大部分是相同的,在这个示例里看着这点重复代码似乎还是可以接受的,但是在真实环境下,重复的代码就不止这一点点了。因为exp2和exp1相比,exp2只是在exp1之上多加了一个条件,那我们有没有方法可以在exp1的基础上再加一个条件赋值给exp2呢?答案当然是可以的。

      表达式扩展类:

    复制代码
     1 public static class ExpressionExt
     2 {
     3     public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
     4     {          
     5         return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, expr2.Body), expr1.Parameters);
     6     }
     7     public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,Expression<Func<T, bool>> expr2)
     8     {
     9         return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, expr2.Body), expr1.Parameters);
    10     }
    11 }
    复制代码

      上面这代码是我们这文章的核心,我在这里顺便解释一下这个And扩展方法它是怎么做的,它这里先是使用Expression类中的静态方法AndAlso把expr1和expr2的主体拼接在一起,如果AndAlso方法返回的是BinaryExpression类型的结果,而dapperLambda的条件参数需要的是Lambda表达式树,所以这里我们需要通过Expression.Lambda方法来构造一个委托类型来创建一个Lambda表达树。

      那现在我们通过上面的扩展方法,再来优化一下我们最初举的例子看下:

    复制代码
    1 Expression<Func<SysUser, bool>> exp1 = s => s.UserName.Contains("1") && s.Age > 0;
    2 Expression<Func<SysUser, bool>> exp2 =exp1.And( s => s.IsEnable == 1);
    3 using (var context = new DbContext().ConnectionString(connString))
    4 {
    5     var result1 = context.Select<SysUser>(exp1).QueryMany();
    6     var result2 = context.Select<SysUser>(exp2).QueryMany();
    7 }
    复制代码

    结束语

     虽然这个扩展方法就只有几行代码,但是如果少了这几行代码,在我们的代码里可能就要上了几十行、几百行代码了。有时解决问题的关键就是那么一个不起眼的东西,但就是这么一个不起眼的东西就能帮我们解决一些大问题。

      说到这,让我想起了一句话——每多学一点知识,就少写一行代码。

  • 相关阅读:
    170601、单例模式的三种水平代码(第三种最佳)
    解决打开pycharm有带图片md文件卡死问题
    Dockerfile 操作
    Docker 命令大全
    MAC
    mac 搭建selenium与ChromeDriver环境
    Mac进行 usr/bin 目录下修改权限问题,operation not permitted
    pytest文档6-fixture之yield实现teardown
    pytest文档5-fixture之conftest.py
    pytest文档4-测试用例setup和teardown
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/5456081.html
Copyright © 2020-2023  润新知