If you’re having multiple separately defined expressions having common lambda parameter like these:
Expression<Func> pre1 = u => u.FirstName != null; Expression<Func> pre2 = u => u.MiddleName != null; Expression<Func> pre3 = u => u.LastName != null;
And trying to combine them into one and to reuse the said parameter like this:
ParameterExpression param = Expression.Parameter(typeof(User), "u"); var predicates = GetPredicates(); var body = predicates.Select(exp => exp.Body) .Aggregate((left, right) => Expression.AndAlso(left, right)); Expression<Func> lambda = Expression.Lambda<Func>(body, param); Func func = lambda.Compile();
Then you’ll likely get an exception:
Unhandled Exception: System.InvalidOperationException: variable ‘u’ of type ‘User’ referenced from scope ”, but it is not defined.
The reason is that spite the lambda parameters have same type and name they’re defined in different expressions thus in different scopes so can’t be simply reused.
What you need to do is to use single parameter across all expressions, in other words to unify/merge/replace their parameters with one:
class ParameterReplacer : ExpressionVisitor { private readonly ParameterExpression _param; private ParameterReplacer(ParameterExpression param) { _param = param; } protected override Expression VisitParameter(ParameterExpression node) { return node.Type == _param.Type ? // if types match on both of ends base.VisitParameter(_param) : // replace node; // ignore } public static T Replace(ParameterExpression param, T exp) where T : Expression { return (T)new ParameterReplacer(param).Visit(exp); } }
And then:
var body = predicates.Select(exp => exp.Body) .Select(exp => ParameterReplacer.Replace(param, exp)) .Aggregate((left, right) => Expression.AndAlso(left, right)); var lambda = Expression.Lambda<Func>(body, param);
That’s it, now compilation will work fine and produce the desired predicate.
Happy expression trees building!