For a recent LINQ-based project I needed to merge branches of multiple expression trees into one. Normally this doesn’t cause any issues, but I wanted to dynamically merge multiple ‘Where’ predicates together with arbitrary logical operators (hope that’s the right term; it sounds about right). I found a great base class called ExpressionVisitor on Matt Warren’s blog. Always keen to reduce the amount of typing (and thinking) I need to do, I couldn’t resist making a couple of helpers. The first allows you to use syntax like this (don’t worry, it gets better…):
MethodCallExpression call = ...; call = ExpressionVisitor<ParameterExpression>.Visit( call, p => p.Type == typeof( T ) ? elementParam : p ) as MethodCallExpression;
Basically it lets you specify a delegate to visit (and change) a single expression type in the tree. Here’s the code (you’ll also need Matt’s ExpressionVisitor source):
public class ExpressionVisitor<T> : ExpressionVisitor where T : Expression { Func<T, Expression> visitor; public ExpressionVisitor( Func<T, Expression> visitor ) { this.visitor = visitor; } public static Expression Visit( Expression exp, Func<T, Expression> visitor ) { return new ExpressionVisitor<T>( visitor ).Visit( exp ); } public static Expression<TDelegate> Visit<TDelegate>( Expression<TDelegate> exp, Func<T, Expression> visitor ) { return (Expression<TDelegate>)new ExpressionVisitor<T>( visitor ).Visit( exp ); } protected override Expression Visit( Expression exp ) { if ( exp is T && visitor != null ) exp = visitor( (T)exp ); return base.Visit( exp ); } }
As a refinement I added a couple of extension methods for more compact syntax. For non-generic types you can do this:
MethodCallExpression call = ...;
call = call.Visit<ParameterExpression, MethodCallExpression>(
p => p.Type == typeof( T ) ? elementParam : p );
For generic types you can do this:
Expression<Func<Profile, bool>> call = ...;
call = call.Visit<ParameterExpression, Func<Profile, bool>>( p => p.Type == typeof( T ) ? elementParam : p );
(However I’d rather the Func<Profile, bool> wasn’t needed in the call to Visit<>() here… I’d hoped it could infer the TDelegate type and let me just specify the ‘T’ type, but it seems it can’t do both together . Maybe I’m missing something obvious, or perhaps it’s a beta 2 bug? Feedback welcome!).
Here’s the code for the extension methods:
public static class ExpressionExtensions { public static Expression Visit<T>( this Expression exp, Func<T, Expression> visitor ) where T : Expression { return ExpressionVisitor<T>.Visit( exp, visitor ); } public static TExp Visit<T, TExp>( this TExp exp, Func<T, Expression> visitor ) where T : Expression where TExp : Expression { return (TExp)ExpressionVisitor<T>.Visit( exp, visitor ); } public static Expression<TDelegate> Visit<T, TDelegate>( this Expression<TDelegate> exp, Func<T, Expression> visitor ) where T : Expression { return ExpressionVisitor<T>.Visit<TDelegate>( exp, visitor ); } }
I’m sure there’s scope for other enhancements too…
[…] an alternative, you can also use the ExpressionVisitor class to iterate the expression tree, as illustrated in other […]