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);