Skip to content

Instantly share code, notes, and snippets.

@bbonkr
Last active June 19, 2025 04:47
Show Gist options
  • Save bbonkr/0de22f99f4fb46c9b6316773e02cfa3b to your computer and use it in GitHub Desktop.
Save bbonkr/0de22f99f4fb46c9b6316773e02cfa3b to your computer and use it in GitHub Desktop.
Combine `or` predicates.
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