如何将多个Expression<Func<T1,T2,bool>>通过OrElse合并为Expression<Func<T2,bool>>
问题原因
你遇到的两个报错本质是表达式树的结构使用错误:
- 不能直接将完整的
Expression<Func<>>类型的Lambda表达式赋值给BinaryExpression,后者只对应Lambda内部的二元运算节点 OrElse只能拼接返回布尔值的表达式节点,不能直接拼接两个完整的Lambda表达式,两个Func类型之间不存在逻辑或运算定义
另外你后续构造Lambda时参数数量不匹配,每个循环里创建的Lambda参数都是独立实例,直接拼接会出现参数引用不匹配的问题。
正确实现
步骤1:定义公共参数
所有拼接的条件复用同一组参数实例,避免参数不匹配:
// 定义两个公共参数,对应原表达式中的n和c var paramN = Expression.Parameter(typeof(TNumbering), "n"); var paramC = Expression.Parameter(typeof(TConfiguration), "c");
步骤2:遍历拼接条件
BinaryExpression combinedBody = null; foreach (var criteria in SelectionCriteria) { // 构造获取配置字段的表达式:criteria.ConfigurationField(c) var configFieldExp = Expression.Invoke( Expression.Constant(criteria.ConfigurationField), paramC ); // 构造获取编号字段的表达式:criteria.NumberingField(n) var numberingFieldExp = Expression.Invoke( Expression.Constant(criteria.NumberingField), paramN ); // 构造不等于判断的二元表达式 var notEqualExp = Expression.NotEqual(configFieldExp, numberingFieldExp); // 用OrElse拼接已有条件 combinedBody = combinedBody == null ? notEqualExp : Expression.OrElse(combinedBody, notEqualExp); }
步骤3:构造Lambda并调用
if (combinedBody == null) { return Result.Failure("Expression not defined"); } // 构造完整的过滤Lambda var filterLambda = Expression.Lambda<Func<TNumbering, TConfiguration, bool>>( combinedBody, paramN, paramC ); // 编译为委托供Linq to Objects使用,若用于EF等IQueryable场景不要编译,直接传入表达式 var filter = filterLambda.Compile(); // 执行过滤 numberingsToRemove = numberings.Where(n => configurations.All(c => filter(n, c))).ToList();
注意事项
如果你的逻辑是用于EF Core等ORM的IQueryable查询,不能使用Expression.Invoke和Compile方法,需要将两个属性的类型从Func<,>改为Expression<Func<,>>,再直接拼接表达式体即可。
内容的提问来源于stack exchange,提问作者Mkov
相关产品推荐
相关产品推荐

