-1

I have 2 lists

List<Expression<Func<MyClass, bool>>> andConditions = new List<Expression<Func<MyClass, bool>>>();

List<Expression<Func<MyClass, bool>>> orConditions = new List<Expression<Func<MyClass, bool>>>();

The first one, I'd like AND between each items, the second one OR between each items. At the end, I'd like combine the 2 lists with a OR between.

Example of result:

exprList1 AND exprList1 OR exprList2 OR exprList2 OR exprList2 

Could you tell me about this?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
TheBoubou
  • 19,487
  • 54
  • 148
  • 236

1 Answers1

0

You can use PredicateBuilder from LINQKit nuget package.

Of all the things that will drive you to manually constructing expression trees, the need for dynamic predicates is the most common in a typical business application. Fortunately, it’s possible to write a set of simple and reusable extension methods that radically simplify this task. This is the role of our PredicateBuilder class.

First install nuget package:

Install-Package LinqKit

After that you can use PredicateBuilder to combine expressions. Long version:

// AND
var combinedAnd = PredicateBuilder.New<MyClass>(true);
foreach (var andCondition in andConditions)
{
    combinedAnd = combinedAnd.And(andCondition);
}

// OR
var combinedOr = PredicateBuilder.New<MyClass>(false);
foreach (var orCondition in orConditions)
{
    combinedOr = combinedOr.Or(orCondition);
}

var finalExpression = combinedAnd.Or(combinedOr);

Short LINQ based version:

var combinedAnd = andConditions
    .Aggregate(
        PredicateBuilder.New<MyClass>(true), 
        (current, andCondition) => current.And(andCondition));
var combinedOr = orConditions
    .Aggregate(
        PredicateBuilder.New<MyClass>(false), 
        (current, orCondition) => current.Or(orCondition));
var finalExpression = combinedAnd.Or(combinedOr);

PredicateBuilder.New<MyClass>(true) returns an initial predicate that returns true. It's suitable behavior to combine predicates with AND operatation because it will create true && predicate_1 && ... && predicate_n result. PredicateBuilder.New<MyClass>(false) is suitable for OR operation.

If you can't use external libraries you can implement methods to combine expressions yourself:

public static class ExpressionExtensions
{
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var parameter = Expression.Parameter(typeof(T), "x");
        var body = Expression.And(
            Expression.Invoke(expr1, parameter),
            Expression.Invoke(expr2, parameter)
        );
        return Expression.Lambda<Func<T, bool>>(body, parameter);
    }

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var parameter = Expression.Parameter(typeof(T), "x");
        var body = Expression.Or(
            Expression.Invoke(expr1, parameter),
            Expression.Invoke(expr2, parameter)
        );
        return Expression.Lambda<Func<T, bool>>(body, parameter);
    }
}

And use it in your code:

var combinedAnd = andConditions.Aggregate((expr1, expr2) => expr1.And(expr2));
var combinedOr = orConditions.Aggregate((expr1, expr2) => expr1.Or(expr2));
var finalExpression = combinedAnd.Or(combinedOr);
Vadim Martynov
  • 8,602
  • 5
  • 31
  • 43