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.

[csharp] using System; using System.Linq; using System.Linq.Expressions; using System.Collections.Generic;

public static class ExpressionBuilder { public static Expression\ > True\ () { return f => true; } public static Expression\ > False\ () { return f => false; }

public static Expression\ Compose\ (this Expression\ first, Expression\ second, Func\ 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\ (merge(first.Body, secondBody), first.Parameters); }

public static Expression\ > And\ ( this Expression\ > first, Expression\ > second) { return first.Compose(second, Expression.And); }

public static Expression\ > Or\ ( this Expression\ > first, Expression\ > second) { return first.Compose(second, Expression.Or); }

public class ParameterRebinder : ExpressionVisitor { private readonly Dictionary\ map;

public ParameterRebinder( Dictionary\ map) { this.map = map??new Dictionary\ (); }

public static Expression ReplaceParameters( Dictionary\ 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); } } } [/csharp]

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.



Wed Feb 13 2013 00:43:48 GMT-0800 (Pacific Standard Time)


Previous page: Updated Release of the Abodit State Machine


Disqus goes here