首页 > 其他分享 >动态构建表达式

动态构建表达式

时间:2023-10-10 15:48:04浏览次数:32  
标签:parameter Visit 构建 visitor 参数 动态 Expression 表达式

问题来源:前端文本输入框以分隔符(比如"aa|bb|cc")传进来的字符串,针对一个字段做的查询条件;由于该字符串分隔符数量不确定,因此需要动态构建出来;

旨在实现例如以下效果:

var users = await _context.Users.Where(s=>s.Name.Contains("aa") || s.Name.Contains("bb") || s.Name.Contains("cc")).ToListAsync();

  

以下是后端代码的相关实现

1.新建两个类如下:

public class PredicateExpressionVisitor : ExpressionVisitor
{
    public ParameterExpression _parameter { get; set; }

    public PredicateExpressionVisitor(ParameterExpression parameter)
    {
        _parameter = parameter;
    }
    protected override Expression VisitParameter(ParameterExpression p)
    {
        return _parameter;
    }

    public override Expression Visit(Expression expression)
    {
        //Visit会根据VisitParameter()方法返回的Expression进行相关变量替换
        return base.Visit(expression);
    }
}


 /// <summary>
 /// Linq表达式扩展方法
 /// </summary> 
 public static class PredicateExtensions
 {
     /// <summary>
     /// 以And合并单个表达式
     /// 此处采用AndAlso实现“最短路径”,避免掉额外且不需要的比较运算式
     /// </summary> 
     public static Expression<Func<T, bool>> MergeAnd<T>(this Expression<Func<T, bool>> leftExpress, Expression<Func<T, bool>> rightExpress)
     {
         //声明传递参数(也就是表达式树里面的参数别名s)
         ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
         //统一管理参数,保证参数一致,否则会报错 
         var visitor = new PredicateExpressionVisitor(parameter);
         //表达式树内容
         Expression left = visitor.Visit(leftExpress.Body);
         Expression right = visitor.Visit(rightExpress.Body);
         //合并表达式
         return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left, right), parameter);
     }

     /// <summary>
     /// 以And合并多个表达式
     /// 此处采用AndAlso实现“最短路径”,避免掉额外且不需要的比较运算式
     /// </summary> 
     public static Expression<Func<T, bool>> MergeAnd<T>(this Expression<Func<T, bool>> express, params Expression<Func<T, bool>>[] arrayExpress)
     {
         if (!arrayExpress?.Any() ?? true) return express;
         //声明传递参数(也就是表达式树里面的参数别名s)
         ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
         //统一管理参数,保证参数一致,否则会报错 
         var visitor = new PredicateExpressionVisitor(parameter);
         Expression<Func<T, bool>> result = null;
         //合并表达式
         foreach (var curExpression in arrayExpress)
         {
             //表达式树内容
             Expression left = visitor.Visit(result.Body);
             Expression right = visitor.Visit(curExpression.Body);
             result = Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left, right), parameter);
         }
         return result;
     }

     /// <summary>
     /// 以Or合并表达式
     /// 此处采用OrElse实现“最短路径”,避免掉额外且不需要的比较运算式
     /// </summary> 
     public static Expression<Func<T, bool>> MergeOr<T>(this Expression<Func<T, bool>> leftExpress, Expression<Func<T, bool>> rightExpress)
     {
         //声明传递参数(也就是表达式树里面的参数别名s)
         ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
         //统一管理参数,保证参数一致,否则会报错 
         var visitor = new PredicateExpressionVisitor(parameter);
         //表达式树内容
         Expression left = visitor.Visit(leftExpress.Body);
         Expression right = visitor.Visit(rightExpress.Body);
         //合并表达式
         return Expression.Lambda<Func<T, bool>>(Expression.OrElse(left, right), parameter);
     }

     /// <summary>
     /// 以Or合并多个表达式
     /// 此处采用AndAlso实现“最短路径”,避免掉额外且不需要的比较运算式
     /// </summary> 
     public static Expression<Func<T, bool>> MergeOr<T>(this Expression<Func<T, bool>> express, params Expression<Func<T, bool>>[] arrayExpress)
     {
         if (!arrayExpress?.Any() ?? true) return express;
         //声明传递参数(也就是表达式树里面的参数别名s)
         ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
         //统一管理参数,保证参数一致,否则会报错 
         var visitor = new PredicateExpressionVisitor(parameter);
         Expression<Func<T, bool>> result = null;
         //合并表达式
         foreach (var curExpression in arrayExpress)
         {
             //表达式树内容
             Expression left = visitor.Visit(result.Body);
             Expression right = visitor.Visit(curExpression.Body);
             result = Expression.Lambda<Func<T, bool>>(Expression.OrElse(left, right), parameter);
         }
         return result;
     }
 }
View Code

 

2.在对应的接口中调用就能实现功能了(这里的search.Name以分隔符|举例,比如"aa|bb|cc")

 //在文件夹下所搜多个文件名包含的查询条件
 if (!string.IsNullOrWhiteSpace(search.Name))
 {
     var names = search.Name.Split('|').ToList();
     Expression<Func<FileInfomation, bool>> expression = default;
     foreach (var name in names)
     {
         if (names.IndexOf(name) == 0)
             expression = s => s.Name.Contains(name);
         else
         {
             Expression<Func<FileInfomation, bool>> expressionNew = s => s.Name.Contains(name);
             expression = expression.MergeOr(expressionNew);
         }
     }
     fileInfos = fileInfos.Where(expression.Compile()).ToList();
 }
View Code

 

标签:parameter,Visit,构建,visitor,参数,动态,Expression,表达式
From: https://www.cnblogs.com/hypothesisxk/p/17754833.html

相关文章

  • Lnton羚通视频分析算法开发平台建立工地人员入侵,构建工地实名制人员通道系统解决方案
    Lnton羚通的算法算力云平台是一款优秀的解决方案,具有突出的特点。它提供高性能、高可靠性、高可扩展性和低成本的特性,使用户能够高效地执行复杂计算任务。此外,平台还提供丰富的算法库和工具,并支持用户上传和部署自定义算法,提升了平台的灵活性和个性化能力。建筑工地的管理一直以来......
  • PostMan环境变量、全局变量、动态参数使用
    一、环境准备postmanmoco[{"description":"登录认证","request":{"uri":"/login","method":"post","forms":{"user":"admin&q......
  • 【C++ Primer】表达式
    一、基础1、左值和右值:当一个对象被用作右值的时候,用的是对象的值(内容);当对象用作左值的时候,用的是对象的身份(在内存中的位置)。   需要用到左值的地方有:赋值运算符需要一个左值作为其左侧运算对象,得到的结果也是左值。取地址符作用与左值对象,返回的指针是右值。解引用和下标运算......
  • Maven构建过程
    清理:删除上一次构建的结果,为下一次构建做好准备编译:Java源程序编译成*.class字节码文件测试:运行提前准备好的测试程序报告:针对测试的结果生成一个全面的信息打包:Java工程(jar包)Web工程(war包)安装:把一个Maven工程经过打包操作生成的工程包存入到Maven仓库......
  • (allure报告定制)动态显示模块名和用例标题
    场景:当自动化测试使用excel测试用例驱动时,动态显示模块名和用例标题就很有用。https://blog.csdn.net/lixiaomei0623/article/details/120273737一、allure报告动态参数化展示模块名和用例标题使用@pytest.mark.parametrize参数化完成数据驱动时,如果标题写死或者使用别名的方......
  • 使用vue-router添加动态路由时遇到的坑
    在开发后台管理的时候,用户登录时需要根据权限来分配路由,这时候可以在路由守卫里通过router.addRoute()方法动态添加路由。importrouterfrom'./router'importstorefrom'./store'importstoragefrom'@/utils/storage'import{asyncRoute}from"@/router/routers";......
  • WinForm 使用委托动态更新数据
    使用委托动态更新数据详细代码//声明一个委托,用于更新消息的文本提示privatedelegatevoidUpdateMsgTextDelegate(stringtext);//定义一个方法,用于更新控件的文本privatevoidUpdateMsgText(stringtext){//判......
  • 动态规划5.4-换根树形动态规划
    一、换根树形动态规划换根树形动态规划又称二次扫描,相较于一般的树形动态规划,有如下特点:以树上不同的节点为根,其解不同求解答案时,不能只求解某一点的信息,而是求解所有点的信息无法通过一次搜索来求解答案二、例题1.[DaimayuanOnlineJudge.距离和]题目描述有一棵\(n\)......
  • 视频融合平台EasyCVR利用视频监控系统构建小区人员出入口管理方案
    安防视频监控平台EasyCVR是一个具有强大拓展性、灵活的视频能力和轻便部署的平台。它支持多种主流标准协议,包括国标GB28181、RTSP/Onvif、RTMP等,还可以支持厂家的私有协议和SDK接入,例如海康Ehome、海大宇等设备的SDK。该平台不仅拥有传统安防视频监控的功能,还具备接入AI智能分析的......
  • angular使用from动态设置验证器(clearValidators、setValidators)
    原文链接:https://www.longkui.site/program/frontend/angularfrom/4787/0.背景调试一个angular的form表单,根据条件动态赋予表单的权限验证。主要介绍clearValidators和setValidators的用法。1.代码初始化代码:1234567891011121314151617181920212......