如何在动态LINQ Expression中组合多个BinaryExpression与Contains条件
解决方案
你不需要将MethodCallExpression转为BinaryExpression,核心原因是你定义的List<BinaryExpression>类型限制过死:所有返回布尔值的表达式(包括BinaryExpression、MethodCallExpression等)都可以作为逻辑运算的操作数,Expression.AndAlso方法的参数只要求是Expression类型,不限制具体子类。
你可以选择以下两种方案实现需求:
方案1:调整条件列表的类型(推荐)
直接将列表类型改为List<Expression>,可以兼容所有类型的布尔条件,后续新增其他非二元表达式条件(比如Any、StartsWith等方法调用条件)也不需要再修改逻辑:
// 1. 调整列表类型,存储所有布尔条件 List<Expression> conditions = new List<Expression>(); // 2. 添加已有的两个二元表达式条件 conditions.Add(nameEqualExpression); // x.Name == "Some_Name" conditions.Add(ageGreaterExpression); // x.Age > 60 // 3. 直接添加Contains对应的MethodCallExpression var containsExpression = Expression.Call(memberExpression, "Contains", null, constantExpression); conditions.Add(containsExpression); // 4. 聚合所有条件,逻辑和之前完全一致 var aggregatedCondition = conditions.Aggregate(Expression.AndAlso); // 5. 构造最终的查询Lambda var parameter = Expression.Parameter(typeof(Person), "x"); var filterLambda = Expression.Lambda<Func<Person, bool>>(aggregatedCondition, parameter); // 执行查询 var result = people.Where(filterLambda);
方案2:不修改原有列表,单独拼接条件
如果你不想改动已有的List<BinaryExpression>相关逻辑,可以先聚合原有二元表达式,再直接和Contains表达式做逻辑与拼接:
// 原有逻辑不变,先聚合所有二元表达式 var aggregatedBinaryCondition = binaryExpressions.Aggregate(Expression.AndAlso); // 直接拼接Contains表达式,不需要类型转换 var containsExpression = Expression.Call(memberExpression, "Contains", null, constantExpression); var finalCondition = Expression.AndAlso(aggregatedBinaryCondition, containsExpression); // 后续构造Lambda的逻辑和之前一致即可
注意事项
如果你的ChildIds类型是IEnumerable<string>而非带实例Contains方法的具体类型(比如List<string>),Contains是Enumerable的扩展方法,需要用以下方式构造表达式,避免运行时报错:
var containsMethod = typeof(Enumerable) .GetMethods(BindingFlags.Public | BindingFlags.Static) .First(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2) .MakeGenericMethod(typeof(string)); var containsExpression = Expression.Call(containsMethod, memberExpression, constantExpression);
内容的提问来源于stack exchange,提问作者chary
相关产品推荐
相关产品推荐

