C# Lambda、Linq表达式树动态构建、合并扩展方法

打印 上一主题 下一主题

主题 552|帖子 552|积分 1656

前言

日常开发时,使用Linq和EF经常会在存在多条件查询,或者说动态条件查询时,便存在合并表达式树的情况。基于这种情况结合一些资料,写了个扩展类,代码如下:
代码实现
  1.     /// <summary>
  2.     /// Linq表达式扩展方法
  3.     /// </summary>
  4.     public static class PredicateExtensions
  5.     {
  6.         /// <summary>
  7.         /// 以And合并单个表达式
  8.         /// 此处采用AndAlso实现“最短路径”,避免掉额外且不需要的比较运算式
  9.         /// </summary>
  10.         public static Expression<Func<T, bool>> MergeAnd<T>(this Expression<Func<T, bool>> leftExpress, Expression<Func<T, bool>> rightExpress)
  11.         {
  12.             //声明传递参数(也就是表达式树里面的参数别名s)
  13.             ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
  14.             //统一管理参数,保证参数一致,否则会报错
  15.             var visitor = new PredicateExpressionVisitor(parameter);
  16.             //表达式树内容
  17.             Expression left = visitor.Visit(leftExpress.Body);
  18.             Expression right = visitor.Visit(rightExpress.Body);
  19.             //合并表达式
  20.             return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left, right), parameter);
  21.         }
  22.         /// <summary>
  23.         /// 以And合并多个表达式
  24.         /// 此处采用AndAlso实现“最短路径”,避免掉额外且不需要的比较运算式
  25.         /// </summary>
  26.         public static Expression<Func<T, bool>> MergeAnd<T>(this Expression<Func<T, bool>> express, params Expression<Func<T, bool>>[] arrayExpress)
  27.         {
  28.             if (!arrayExpress?.Any() ?? true) return express;
  29.             //声明传递参数(也就是表达式树里面的参数别名s)
  30.             ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
  31.             //统一管理参数,保证参数一致,否则会报错
  32.             var visitor = new PredicateExpressionVisitor(parameter);
  33.             Expression<Func<T, bool>> result = null;
  34.             //合并表达式
  35.             foreach (var curExpression in arrayExpress)
  36.             {
  37.                 //表达式树内容
  38.                 Expression left = visitor.Visit(result.Body);
  39.                 Expression right = visitor.Visit(curExpression.Body);
  40.                 result = Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left, right), parameter);
  41.             }
  42.             return result;
  43.         }
  44.         /// <summary>
  45.         /// 以Or合并表达式
  46.         /// 此处采用OrElse实现“最短路径”,避免掉额外且不需要的比较运算式
  47.         /// </summary>
  48.         public static Expression<Func<T, bool>> MergeOr<T>(this Expression<Func<T, bool>> leftExpress, Expression<Func<T, bool>> rightExpress)
  49.         {
  50.             //声明传递参数(也就是表达式树里面的参数别名s)
  51.             ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
  52.             //统一管理参数,保证参数一致,否则会报错
  53.             var visitor = new PredicateExpressionVisitor(parameter);
  54.             //表达式树内容
  55.             Expression left = visitor.Visit(leftExpress.Body);
  56.             Expression right = visitor.Visit(rightExpress.Body);
  57.             //合并表达式
  58.             return Expression.Lambda<Func<T, bool>>(Expression.OrElse(left, right), parameter);
  59.         }
  60.         /// <summary>
  61.         /// 以Or合并多个表达式
  62.         /// 此处采用AndAlso实现“最短路径”,避免掉额外且不需要的比较运算式
  63.         /// </summary>
  64.         public static Expression<Func<T, bool>> MergeOr<T>(this Expression<Func<T, bool>> express, params Expression<Func<T, bool>>[] arrayExpress)
  65.         {
  66.             if (!arrayExpress?.Any() ?? true) return express;
  67.             //声明传递参数(也就是表达式树里面的参数别名s)
  68.             ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
  69.             //统一管理参数,保证参数一致,否则会报错
  70.             var visitor = new PredicateExpressionVisitor(parameter);
  71.             Expression<Func<T, bool>> result = null;
  72.             //合并表达式
  73.             foreach (var curExpression in arrayExpress)
  74.             {
  75.                 //表达式树内容
  76.                 Expression left = visitor.Visit(result.Body);
  77.                 Expression right = visitor.Visit(curExpression.Body);
  78.                 result = Expression.Lambda<Func<T, bool>>(Expression.OrElse(left, right), parameter);
  79.             }
  80.             return result;
  81.         }
  82.     }
复制代码
使用例子
  1.     class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             var models = new List<JsonData>() { new JsonData() { Id = "001", Name = "One" }, new JsonData() { Id = "002", Name = "Tow" } };
  6.             Console.WriteLine($"未处理集合:{string.Join(',', models.Select(o => o.Id))}");
  7.             //表达式1
  8.             Expression<Func<JsonData, bool>> expression1 = t => t.Id == "001";
  9.             //表达式2
  10.             Expression<Func<JsonData, bool>> expression2 = t => t.Name == "Tow";
  11.             //合并成 t => t.Id=="001" && t.Name=="One"
  12.             Expression<Func<JsonData, bool>> allEexpression = expression1.MergeAnd(expression2);
  13.             Console.WriteLine(allEexpression.Body.ToString());
  14.             Console.WriteLine($"已处理集合(And):{string.Join(',', models.Where(expression1.MergeAnd(expression2).Compile()).Select(o => o.Id))}");
  15.             //合并成 t => t.Id=="001" || t.Name=="One"
  16.             allEexpression = expression1.MergeOr(expression2);
  17.             Console.WriteLine(allEexpression.Body.ToString());
  18.             Console.WriteLine($"已处理集合(Or):{string.Join(',', models.Where(allEexpression.Compile()).Select(o => o.Id))}");
  19.             Console.ReadKey();
  20.         }
  21.     }
  22.      
  23.     public class JsonData
  24.     {
  25.         public string Id { get; set; }
  26.         public string Name { get; set; }
  27.     }
复制代码
结果


相关资料

MSDN Expression类
MSDN  ExpressionVisitor类

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用户云卷云舒

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表