Dynamically building 'Or' Expressions in LINQ
One common question on Stackoverflow concerns the creation of a LINQ expression that logically Ors together a set of predicates. The need stated is to be able to build such an expression dynamically. Creating the 'And' version is easy, you simply stack multiple '.Where' clauses onto an expression as you add each predicate. You can't do the same for 'Or'. The common responses are 'use LINQKit' or 'use Dynamic LINQ'. LINQKit however adds the unfortunate '.AsExpandable()' into the expression which can cause problems in some circumstances, and Dynamic LINQ is not strongly-typed so doesn't survive renaming operations. Neither answer is ideal.
But, there is another way, using a bit of Expression tree manipulation you can build an 'Or' expression dynamically while staying strongly-typed. The code below achieves this.
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
public static class ExpressionBuilder
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false;
}
public static Expression<T> Compose<T>(this Expression<T> first,
Expression<T> second, Func<Expression, Expression, Expression>
merge)
{
// build parameter map (from parameters of second to parameters of first)
var map = first.Parameters .Select((f, i) => new { f, s = second.Parameters[i] }) .ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with parameters from
// the first
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
// apply composition of lambda expression bodies to parameters from
// the first expression
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters); }
public static Expression<Func<T, bool>> And<T>( this
Expression<Func<T, bool>> first, Expression<Func<T, bool>>
second) { return first.Compose(second, Expression.And); }
public static Expression<Func<T, bool>> Or<T>( this
Expression<Func<T, bool>> first, Expression<Func<T, bool>>
second) { return first.Compose(second, Expression.Or); }
public class ParameterRebinder : ExpressionVisitor { private readonly
Dictionary<ParameterExpression, ParameterExpression> map;
public ParameterRebinder( Dictionary<ParameterExpression,
ParameterExpression> map) { this.map = map??new
Dictionary<ParameterExpression,ParameterExpression>(); }
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression replacement;
if (map.TryGetValue(p, out replacement)) { p = replacement; } return base.VisitParameter(p);
}
}
}
NB Some of the ideas in this case from other blog posts, I can't find them right now but if part of this was your idea I'd be happy to add a link to your blog.