如何基于输入参数动态创建带OR逻辑的LINQ查询?
问题
假设我有一个整数列表,函数接收两个条件输入参数用于过滤,参数结构如下:
public class Input { public string Operation = "less than"; // 可取值 <=, >=, !=, ==, <, > 等 public int Filter = 9; }
我希望根据传入的条件进行动态过滤,且过滤逻辑为OR关系。请问如何动态创建LINQ查询,避免如下所示的硬编码所有条件组合:
/* Input one = { Operation = "less than" , Filter = 9 } Input two = { Operation = "equal to", Filter =10 } int[] arrayToFilter = { 1,2,3,4,5,6,7,8,9,10,11,12 } */ public int[] MyFilter(Input one, Input two, int[] arrayToFilter) { if (one.Operation == "less than" && two.Operation == "equal to") { return arrayToFilter.Where(x => x < one.Filter || x == two.Filter).ToArray(); } if (one.Operation == "less than or equal to" && two.Operation == "greater than") { return arrayToFilter.Where(x => x <= one.Filter || x > two.Filter).ToArray(); } // 其余所有组合(如何避免这种写法?) return arrayToFilter; }
解决方案
方法一:委托映射+动态组合(适合内存集合)
先把每个Input条件转换成独立的判断委托,再用OR逻辑组合,完全避免硬编码组合场景:
- 编写操作符到委托的映射方法:
private Func<int, bool> GetFilterPredicate(Input input) { return input.Operation switch { "less than" => x => x < input.Filter, "less than or equal to" => x => x <= input.Filter, "greater than" => x => x > input.Filter, "greater than or equal to" => x => x >= input.Filter, "equal to" => x => x == input.Filter, "not equal to" => x => x != input.Filter, _ => x => true // 默认返回true,即不过滤该条件 }; }
- 在过滤方法中组合OR逻辑:
public int[] MyFilter(Input one, Input two, int[] arrayToFilter) { var predicateOne = GetFilterPredicate(one); var predicateTwo = GetFilterPredicate(two); // 满足任意一个条件即可保留 return arrayToFilter.Where(x => predicateOne(x) || predicateTwo(x)).ToArray(); }
这种方式的优势是:新增操作符只需在映射方法里加分支,无需修改过滤逻辑,维护成本极低。
方法二:表达式树构建(适合EF等IQueryable场景)
如果你的数据源是EF这类需要生成SQL查询的IQueryable,用表达式树可以让过滤逻辑在数据库端执行,避免内存全量加载:
- 生成单个条件的表达式:
private Expression<Func<int, bool>> GetFilterExpression(Input input) { var parameter = Expression.Parameter(typeof(int), "x"); var constant = Expression.Constant(input.Filter); var body = input.Operation switch { "less than" => Expression.LessThan(parameter, constant), "less than or equal to" => Expression.LessThanOrEqual(parameter, constant), "greater than" => Expression.GreaterThan(parameter, constant), "greater than or equal to" => Expression.GreaterThanOrEqual(parameter, constant), "equal to" => Expression.Equal(parameter, constant), "not equal to" => Expression.NotEqual(parameter, constant), _ => Expression.Constant(true) }; return Expression.Lambda<Func<int, bool>>(body, parameter); }
- 合并两个表达式的OR逻辑:
public int[] MyFilter(Input one, Input two, int[] arrayToFilter) { var exprOne = GetFilterExpression(one); var exprTwo = GetFilterExpression(two); // 合并两个表达式的OR判断 var combinedExpr = Expression.Lambda<Func<int, bool>>( Expression.OrElse(exprOne.Body, exprTwo.Body), exprOne.Parameters.Single() ); return arrayToFilter.AsQueryable().Where(combinedExpr).ToArray(); }
内容的提问来源于stack exchange,提问作者just-an-average-programmer
相关产品推荐
相关产品推荐

