C# Linq、Lambda表达式树动态构建、合并条件扩展方法
前言
日常开发时,使用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; }
}
结果
相关资料
C# Linq、Lambda表达式树动态构建、合并条件扩展方法的更多相关文章
- 通过LINQ表达式树动态构建查询条件
第一种方法: public static class PredicateExtensions { public static Expression<Func<T, bool>> ...
- LINQ to SQL 运行时动态构建查询条件
在进行数据查询时,经常碰到需要动态构建查询条件.使用LINQ实现这个需求可能会比以前拼接SQL语句更麻烦一些.本文介绍了3种运行时动态构建查询条件的方法.本文中的例子最终实现的都是同一个功能,从Nor ...
- C# Lambda表达式详解,及Lambda表达式树的创建
最近由于项目需要,刚刚学完了Action委托和Func<T>委托,发现学完了委托就必须学习lambda表达式,委托和Lambda表达式联合起来,才能充分的体现委托的便利.才能使代码更加简介 ...
- 将简单的lambda表达式树转为对应的sqlwhere条件
1.Lambda的介绍 园中已经有很多关于lambda的介绍了.简单来讲就是vs编译器给我带来的语法糖,本质来讲还是匿名函数.在开发中,lambda给我们带来了很多的简便.关于lambda的演变过程可 ...
- EntityFramework动态多条件查询与Lambda表达式树
在常规的信息系统中, 我们有需要动态多条件查询的情况, 例如UI上有多个选择项可供用户选择多条件查询数据. 那么在.net平台Entity Framework下, 我们用Lambd ...
- 表达式树动态拼接lambda
动态拼接lambda表达式树 前言 最近在优化同事写的代码(我们的框架用的是dapperLambda),其中有一个这样很普通的场景——界面上提供了一些查询条件框供用户来进行过滤数据.由于dappe ...
- 动态拼接lambda表达式树
前言 最近在优化同事写的代码(我们的框架用的是dapperLambda),其中有一个这样很普通的场景——界面上提供了一些查询条件框供用户来进行过滤数据.由于dapperLambda按条件查询时是传入表 ...
- Lambda表达式树构建(上)
概述 Lambda是C#常用的语句,采用委托等方式,来封装真实的代码块.Lambda其实就是语法糖,是一个匿名函数,是一种高效的类似于函数式编程的表达式,Lambda简化了开发中需要编写的代码量.它可 ...
- 追根溯源之Linq与表达式树
一.什么是表达式树? 首先来看下官方定义(以下摘录自巨硬官方文档) 表达式树表示树状数据结构中的代码,其中每个节点都是表达式,例如,方法调用或诸如的二进制操作x < y. 您可以编译 ...
- C#学习笔记(九):LINQ和表达式树
LINQ LINQ:语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展.它允许编写C#或者Visual Basic代码以查询数据库相同 ...
随机推荐
- 【FAQ】视频编辑服务常见问题及解答
Q1问题描述 1. 访问贴纸等素材的时候提示"网络异常,请重试"怎么办? 2. 使用AI能力时,提示"errorCode:20124 errorMsg:Method no ...
- Rome反序列化链分析
环境搭建 <dependencies> <dependency> <groupId>junit</groupId> <artifactId> ...
- Sample上新,从API 8开始支持!速来拿走
原文:https://mp.weixin.qq.com/s/TxUOSXySZRwQaECenxt-Og ,点击链接查看更多技术内容. 搭载API 8的新SDK已经发布.围绕着新SDK,官方贴心地输出 ...
- 第十九篇:Django ORM外键关联关系
一.一对多的创建 二.一对多跨表操作 三.创建多对多 四.Ajax处识 五.模板继承与导入 六.自定义分页
- 安装CentOS-6.3-i386-minimal
服务器开发者都离不开linux,这里一步步讲下linux安装和开发环境部署 一.下载安装镜像文件 这里以安装CentOS-6.3-i386-minimal为例,这个自带安装软件最少,简单而小巧,偏于你 ...
- 重新整理数据结构与算法(c#)——算法套路k克鲁斯算法[三十]
前言 这个和前面一节有关系,是这样子的,前面是用顶点作为参照条件,这个是用边作为参照条件. 正文 图解如下: 每次选择最小的边. 但是会遇到一个小问题,就是会构成回路. 比如说第四步中,最小边是CE, ...
- gitee基于webhooks实现前端简单自动化部署
1.为什么采用自动化部署 简而言之,程序员优秀传统:懒 =>高级生产力. 基于gitee进行的自动化部署,服务器环境为Ubuntu 基于webhooks进行的自动化部署更加轻快便捷 2.部署步骤 ...
- [GPT] 哪些职业面临 AI 威胁?
随着人工智能技术的不断发展和应用,一些重复性.机械化或标准化程度高的职业可能会面临被自动化取代的威胁.例如: 工厂生产线上的装配工人,因为许多工厂已经开始使用自动化机器人完成装配任务: 行政助理, ...
- WPF 不安装 WindowsAppSDK 使用 WinRT 功能的方法
安装 Microsoft.WindowsAppSDK 库会限制应用程序只能分发 windows 10 应用,如果自己的应用程序依然需要兼容 Win7 等旧系统,那直接采用安装 WindowsAppSD ...
- Azure 无服务器 Function 函数计算服务 dotnet core 3.1 创建和部署入门
本文用的是 世纪互联 的 Azure.cn 版本,这个版本因为是在国内,所以网速会快超级超级多.使用 世纪互联 的版本需要一块钱哦,用一块钱就能进入一个月的免费试用.本文主要告诉小伙伴如何使用 Azu ...