Last active
June 19, 2025 04:47
-
-
Save bbonkr/0de22f99f4fb46c9b6316773e02cfa3b to your computer and use it in GitHub Desktop.
Combine `or` predicates.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class PredicateOrGroupBuilder<T> | |
{ | |
private readonly List<Expression<Func<T, bool>>> predicates; | |
public PredicateOrGroupBuilder() | |
{ | |
predicates = new(); | |
} | |
public PredicateOrGroupBuilder<T> AddPredicate(Expression<Func<T, bool>> predicate) | |
{ | |
if (predicate != null) | |
{ | |
predicates.Add(predicate); | |
} | |
return this; | |
} | |
public PredicateOrGroupBuilder<T> AddPredicates(params Expression<Func<T, bool>>[] predicateItems) | |
{ | |
if (predicateItems != null) | |
{ | |
foreach (var predicate in predicateItems) | |
{ | |
AddPredicate(predicate); | |
} | |
} | |
return this; | |
} | |
public bool CanBuild() => predicates.Any(x => x != null); | |
public Expression<Func<T, bool>> Build() | |
{ | |
if (!CanBuild()) | |
{ | |
return x => true; | |
} | |
Expression<Func<T, bool>> result = null; | |
Expression<Func<T, bool>> exprLeft = x => false; | |
foreach (var expr in predicates.Where(x => x != null)) | |
{ | |
if (result != null) | |
{ | |
exprLeft = result; | |
} | |
result = Combine(exprLeft, expr, Expression.OrElse); | |
} | |
return result; | |
} | |
private static Expression<Func<T, bool>> Combine( | |
Expression<Func<T, bool>> left, | |
Expression<Func<T, bool>> right, | |
Func<Expression, Expression, BinaryExpression> merge) | |
{ | |
var parameter = Expression.Parameter(typeof(T)); | |
var leftVisitor = new ReplaceParameterVisitor(left.Parameters[0], parameter); | |
var rightVisitor = new ReplaceParameterVisitor(right.Parameters[0], parameter); | |
var leftExpr = leftVisitor.Visit(left.Body); | |
var rightExpr = rightVisitor.Visit(right.Body); | |
var body = merge(leftExpr!, rightExpr!); | |
return Expression.Lambda<Func<T, bool>>(body, parameter); | |
} | |
private sealed class ReplaceParameterVisitor : ExpressionVisitor | |
{ | |
private readonly ParameterExpression _oldParameter; | |
private readonly ParameterExpression _newParameter; | |
public ReplaceParameterVisitor(ParameterExpression oldParameter, ParameterExpression newParameter) | |
{ | |
_oldParameter = oldParameter; | |
_newParameter = newParameter; | |
} | |
protected override Expression VisitParameter(ParameterExpression node) | |
{ | |
return node == _oldParameter ? _newParameter : base.VisitParameter(node); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment