前言

日常开发时,使用Linq和EF经常会在存在多条件查询,或者说动态条件查询时,便存在合并表达式树的情况。基于这种情况结合一些资料,写了个扩展类,代码如下:

代码实现

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

使用例子

    class Program
{ static void Main(string[] args)
{
var models = new List<JsonData>() { new JsonData() { Id = "001", Name = "One" }, new JsonData() { Id = "002", Name = "Tow" } }; Console.WriteLine($"未处理集合:{string.Join(',', models.Select(o => o.Id))}");
//表达式1
Expression<Func<JsonData, bool>> expression1 = t => t.Id == "001";
//表达式2
Expression<Func<JsonData, bool>> expression2 = t => t.Name == "Tow";
//合并成 t => t.Id=="001" && t.Name=="One"
Expression<Func<JsonData, bool>> allEexpression = expression1.MergeAnd(expression2);
Console.WriteLine(allEexpression.Body.ToString());
Console.WriteLine($"已处理集合(And):{string.Join(',', models.Where(expression1.MergeAnd(expression2).Compile()).Select(o => o.Id))}");
//合并成 t => t.Id=="001" || t.Name=="One"
allEexpression = expression1.MergeOr(expression2);
Console.WriteLine(allEexpression.Body.ToString());
Console.WriteLine($"已处理集合(Or):{string.Join(',', models.Where(allEexpression.Compile()).Select(o => o.Id))}"); Console.ReadKey();
}
} public class JsonData
{
public string Id { get; set; }
public string Name { get; set; }
}

结果

相关资料

MSDN Expression类
MSDN ExpressionVisitor类

C# Linq、Lambda表达式树动态构建、合并条件扩展方法的更多相关文章

  1. 通过LINQ表达式树动态构建查询条件

    第一种方法: public static class PredicateExtensions { public static Expression<Func<T, bool>> ...

  2. LINQ to SQL 运行时动态构建查询条件

    在进行数据查询时,经常碰到需要动态构建查询条件.使用LINQ实现这个需求可能会比以前拼接SQL语句更麻烦一些.本文介绍了3种运行时动态构建查询条件的方法.本文中的例子最终实现的都是同一个功能,从Nor ...

  3. C# Lambda表达式详解,及Lambda表达式树的创建

    最近由于项目需要,刚刚学完了Action委托和Func<T>委托,发现学完了委托就必须学习lambda表达式,委托和Lambda表达式联合起来,才能充分的体现委托的便利.才能使代码更加简介 ...

  4. 将简单的lambda表达式树转为对应的sqlwhere条件

    1.Lambda的介绍 园中已经有很多关于lambda的介绍了.简单来讲就是vs编译器给我带来的语法糖,本质来讲还是匿名函数.在开发中,lambda给我们带来了很多的简便.关于lambda的演变过程可 ...

  5. EntityFramework动态多条件查询与Lambda表达式树

              在常规的信息系统中, 我们有需要动态多条件查询的情况, 例如UI上有多个选择项可供用户选择多条件查询数据. 那么在.net平台Entity Framework下, 我们用Lambd ...

  6. 表达式树动态拼接lambda

    动态拼接lambda表达式树   前言 最近在优化同事写的代码(我们的框架用的是dapperLambda),其中有一个这样很普通的场景——界面上提供了一些查询条件框供用户来进行过滤数据.由于dappe ...

  7. 动态拼接lambda表达式树

    前言 最近在优化同事写的代码(我们的框架用的是dapperLambda),其中有一个这样很普通的场景——界面上提供了一些查询条件框供用户来进行过滤数据.由于dapperLambda按条件查询时是传入表 ...

  8. Lambda表达式树构建(上)

    概述 Lambda是C#常用的语句,采用委托等方式,来封装真实的代码块.Lambda其实就是语法糖,是一个匿名函数,是一种高效的类似于函数式编程的表达式,Lambda简化了开发中需要编写的代码量.它可 ...

  9. 追根溯源之Linq与表达式树

    一.什么是表达式树?   首先来看下官方定义(以下摘录自巨硬官方文档)   表达式树表示树状数据结构中的代码,其中每个节点都是表达式,例如,方法调用或诸如的二进制操作x < y.   您可以编译 ...

  10. C#学习笔记(九):LINQ和表达式树

    LINQ LINQ:语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展.它允许编写C#或者Visual Basic代码以查询数据库相同 ...

随机推荐

  1. Windows 杀毒简单有效的方式

    Windows 电脑杀毒通常会选择杀毒软件,这样太笨重,且容易占内存和存在流氓软件侵入. 推荐使用 Windows 自带的恶意软件删除工具 按住 Win + R 键,弹出运行窗口,输入 mrt. 系统 ...

  2. char * 、BSTR、long、wchar_t *、LPCWSTR、string、QString、CStringA类型转换

    char* 转 BSTR char* s1 = "zhangsan"; CString s2 = CString(s1); BSTR s3 = s2.AllocSysString( ...

  3. Qt操作ini文件

    操作文件,无非就是读与写,以下为Qt读写ini文件的代码. demo: #include "widget.h" #include <QApplication> #inc ...

  4. openGauss2.1.0在openEuler 20.03 LTS SP2 安装后,yum无法使用的问题解决

    openGauss2.1.0 在 openEuler 20.03 LTS SP2 安装后,yum 无法使用的问题解决 一.环境描述 操作系统: openEuler 20.03 LTS openEule ...

  5. HarmonyOS:Neural Network Runtime对接AI推理框架开发指导

      场景介绍 Neural Network Runtime作为AI推理引擎和加速芯片的桥梁,为AI推理引擎提供精简的Native接口,满足推理引擎通过加速芯片执行端到端推理的需求. 本文以图1展示的A ...

  6. sql 语句系列(计算一个季度的开始日期和结束日期)[八百章之第二十三章]

    前言 很多时候,我们进行数据库查询的时候,查询一个季度的财务报表的时候. 比如说查询2020年第一季度的单子,可能传入后台的就是20201,表示的就是20201第一季度,这时候我们要转换为日期. se ...

  7. docker 应用篇————nginx 例子[六]

    前言 简单整理一下nginx 例子. 正文 拉取nginx 镜像. docker pull nginx 那么会拉取nginx:latest 这个. 如果需要其他的,可以去官网查询一下. 2.docke ...

  8. Go 单元测试之mock接口测试

    目录 一.gomock 工具介绍 二.安装 三.使用 3.1 指定三个参数 3.2 使用命令为接口生成 mock 实现 3.3 使用make 命令封装处理mock 四.接口单元测试步骤 三.小黄书Se ...

  9. 百度unit闲聊机器人

    import json import random import requests # client_id 为官网获取的AK, client_secret 为官网获取的SK client_id = & ...

  10. 顺通鞋服ERP库存管理系统

    鞋服ERP库存管理系统是专门为鞋服行业设计的企业资源规划软件,它提供了一系列库存管理功能,帮助鞋服企业有效管理库存流程和提升库存管理效率.以下是一些鞋服ERP库存管理系统常见的功能和特点: 1. 库存 ...