NET Lambda表达式工具类
帮助类

using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using xFramework.Enums; using xFramework.Extends; namespace Commx.Utilx { /// <summary> /// 表达式工具类 /// </summary> public static class ExpressionUtil { /// <summary> /// 把 查询对象 转换成 拉姆达表达式 /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="TSearch"></typeparam> /// <param name="searchData"></param> /// <returns></returns> public static Func<T, bool> ConvertWhereLambda<T, TSearch>(TSearch searchData) { // x => true Expression<Func<T, bool>> where = xBiz => true; if (searchData == null) return where.Compile(); var tPropertityArr = typeof(T).GetProperties(); var tsearchPropertityArr = typeof(TSearch).GetProperties(); //构建Lambda表达式 x => var parameter = Expression.Parameter(typeof(T), "x"); foreach (var itemPropertity in tsearchPropertityArr) { var fieldName = itemPropertity.Name; if (fieldName == "ROWUID") continue; var contains = tPropertityArr.FirstOrDefault(x => x.Name == fieldName); if (contains == null) continue; var checkTuple = itemPropertity.CheckValidValue(searchData); if (!checkTuple.isValid) continue; // 表达式左侧 like: p.Name var left = Expression.PropertyOrField(parameter, fieldName); // 表达式右侧,比较值, like '张三' var fieldValue = checkTuple.value; var right = Expression.Constant(fieldValue); // 表达式连接符 Expression constant; // 属性的连接符 var searchConditionEnum = itemPropertity.GetSearchConditionAttribute(); // 属性的连接符 Convert 表达式连接符 switch (searchConditionEnum) { case SearchConditionEnum.Gt: constant = Expression.GreaterThan(left, right); break; case SearchConditionEnum.Gte: constant = Expression.GreaterThanOrEqual(left, right); break; case SearchConditionEnum.Lt: constant = Expression.LessThan(left, right); break; case SearchConditionEnum.Lte: constant = Expression.LessThanOrEqual(left, right); break; case SearchConditionEnum.DateRange: var itemValue = right.Value; if (itemValue == null) continue; var itemDateArr = itemValue as string[]; var tuple = itemDateArr.ConvertArrToDateTuple(); var itemStartDateBoo = tuple.firstBoo; var itemStartDate = tuple.firstDate; var itemEndDateBoo = tuple.secondBoo; var itemEndDate = tuple.secondDate; if (itemStartDateBoo && itemEndDateBoo) { // x => x.Date >= yesterday var itemLeft = Expression.Constant(itemStartDate); var itemLeftConstant = Expression.GreaterThanOrEqual(left, itemLeft); // x => x.Date <= tomorrow var itemRight = Expression.Constant(itemEndDate); var itemRightConstant = Expression.LessThanOrEqual(left, itemRight); constant = Expression.And(itemLeftConstant, itemRightConstant); } else if (itemStartDateBoo && !itemEndDateBoo) { // x => x.Date >= yesterday var itemLeft = Expression.Constant(itemStartDate); constant = Expression.GreaterThanOrEqual(left, itemLeft); } else if (!itemStartDateBoo && itemEndDateBoo) { // x => x.Date >= yesterday var itemRight = Expression.Constant(itemEndDate); constant = Expression.GreaterThanOrEqual(left, itemRight); } else { constant = null; } break; case SearchConditionEnum.In: constant = CaseIn(itemPropertity, left, right); break; case SearchConditionEnum.Equals: default: constant = Expression.Equal(left, right); break; } if (constant != null) where = where.And(Expression.Lambda<Func<T, bool>>(constant, parameter)); } return where.Compile(); } /// <summary> /// 特殊处理 In: 集合/数组/字符串/数字 /// </summary> /// <param name="itemPropertity"></param> /// <param name="left"></param> /// <param name="right"></param> /// <returns></returns> private static Expression CaseIn(PropertyInfo itemPropertity, MemberExpression left, ConstantExpression right) { Expression constant; var propertyType = itemPropertity.PropertyType; // like 查询,需要调用外部int或string的Contains方法 MethodInfo method = null; if (propertyType.Name.Contains("List") || propertyType.IsArray) { method = propertyType.GenericTypeArguments.FirstOrDefault() == typeof(int) ? typeof(List<int>).GetMethod("Contains", new Type[] { typeof(int) }) : typeof(List<string>).GetMethod("Contains", new Type[] { typeof(string) }); constant = Expression.Call(right, method, left); } else { // TODO: 如果值为null,会引发空异常 method = propertyType == typeof(int) ? typeof(int).GetMethod("Contains", new Type[] { typeof(int) }) : typeof(string).GetMethod("Contains", new Type[] { typeof(string) }); constant = Expression.Call(left, method, right); } return constant; } public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge) { // build parameter map (from parameters of second to parameters of first) var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); // replace parameters in the second lambda expression with parameters from the first var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); // apply composition of lambda expression bodies to parameters from the first expression return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters); } public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) { return first.Compose(second, Expression.And); } } public class ParameterRebinder : ExpressionVisitor { private readonly Dictionary<ParameterExpression, ParameterExpression> map; public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) { this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>(); } public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) { return new ParameterRebinder(map).Visit(exp); } protected override Expression VisitParameter(ParameterExpression p) { ParameterExpression replacement; if (map.TryGetValue(p, out replacement)) { p = replacement; } return base.VisitParameter(p); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2019-09-03 Regex 提取字符串中重复数据且格式化显示
2019-09-03 Regex 常见语法