Search code examples
c#linqexpression-trees

Expression.Lambda specify ParameterExpression of sub type


I want to join some expressions with OrElse, this one:

Expression<Func<Customer, bool>> extraWhere = x => x.ExtraFields.Any(a => a.Value.Contains(filterText));

with this code:

var buildWhereColumns = BuildWhereColumns<Customer>(columns, filterText);
var combined = Expression.OrElse(buildWhereColumns.Body, extraWhere.Body);
var paramX = Expression.Parameter(typeof(Customer), "x");
var replacerX = new ParameterReplacer(paramX);
var newcombined = replacerX.Visit(combined);

var lambda = Expression.Lambda<Func<Customer, bool>>(newcombined, paramX);

I get an ArgumentException on the replacerX.Visit because it sees the 'a' in the Any as a Customer. How do I specify the (ParameterExpression?)type of a?

The ParameterReplacer:

class ParameterReplacer : ExpressionVisitor
{
    private readonly ParameterExpression parameter;

    internal ParameterReplacer(ParameterExpression parameter)
    {
        this.parameter = parameter;
    }

    protected override Expression VisitParameter
        (ParameterExpression node)
    {
        return parameter;
    }
}

Solution

  • Thanks to the comment of Titian Cernicova-Dragomir I solved it by fixing the ParameterReplacer. I added an extra ParameterExpression:

    var paramX = Expression.Parameter(typeof(Customer), "x");
    var paramA = Expression.Parameter(typeof(ExtraFields), "a");
    var replacerX = new ParameterReplacer(paramX, paramA);
    var newcombined = replacerX.Visit(combined);
    

    And the ParameterReplacer

    class ParameterReplacer : ExpressionVisitor
    {
        private readonly ParameterExpression[] parameter;
    
        internal ParameterReplacer(params ParameterExpression[] parameter)
        {
            this.parameter = parameter;
        }
    
        protected override Expression VisitParameter
            (ParameterExpression node)
        {
            return parameter.Single(x => x.Type == node.Type);
        }
    }