如何在C#中构建复合表达式实现多字段不等判断的All查询逻辑
C# 表达式树拼接OrElse报错解决方案
错误原因
你无法直接对两个Expression<Func<>>类型的Lambda表达式执行OrElse运算:OrElse对应C#中的||运算符,仅支持对返回布尔值的表达式节点进行拼接,你传入的是完整的Lambda委托类型对象,自然没有对应的运算符实现,因此触发报错。
解决思路
统一所有条件使用的参数实例,提取每个判断逻辑的布尔表达式体进行拼接,最后再封装为完整的Lambda表达式即可。
修正后的代码示例
// 提前定义All遍历配置项时的统一参数 ParameterExpression configParam = Expression.Parameter(typeof(TConfiguration), "c"); // 把表达式构造逻辑放到Where的委托内,捕获当前遍历的numbering对象 numberingsToRemove = numberingsToRemove.Where(n => { Expression combinedOr = null; foreach (var criteria in SelectionCriteria) { // 提取配置项的字段访问表达式 Expression configField = Expression.Invoke(criteria.ConfigurationField, configParam); // 提取当前numbering的字段访问表达式 Expression numberingField = Expression.Invoke(criteria.NumberingField, Expression.Constant(n)); // 构造不等判断的布尔表达式 BinaryExpression notEqualExp = Expression.NotEqual(configField, numberingField); // 拼接Or逻辑 combinedOr = combinedOr == null ? notEqualExp : Expression.OrElse(combinedOr, notEqualExp); } if (combinedOr == null) { // 按你的业务逻辑处理空条件的情况 return Result.Failure(string.Format(Errors.NumberingFieldSelectionNotDefined, $"{shipper}:{GetType().FullName}")).IsFailed; } // 拼接为针对配置项的Lambda表达式 var checkLambda = Expression.Lambda<Func<TConfiguration, bool>>(combinedOr, configParam); // 编译后传入All方法 return configsThatStay.All(checkLambda.Compile()); });
注意事项
- 所有参与拼接的表达式必须使用同一个
ParameterExpression实例作为参数,不能每次循环新建参数,否则会被表达式树识别为不同的变量,触发运行时错误。 - 如果这段逻辑需要给EF Core等ORM框架执行(不能在表达式中调用
Compile方法),可以自定义ExpressionVisitor替换Lambda参数,避免使用Invoke调用,适配ORM的表达式解析规则。
内容的提问来源于stack exchange,提问作者Mkov
相关产品推荐
相关产品推荐

