Search code examples
c#linqexpression-trees

Building a list of expressions via Expression Trees


I have the following method which builds an expression based on a column name and value:

public Func<TSource, bool> SimpleComparison<TSource>(string property, object value)
{
    var type = typeof (TSource);
    var pe = Expression.Parameter(type, "p");
    var propertyReference = Expression.Property(pe, property);
    var constantReference = Expression.Constant(value);
    return Expression.Lambda<Func<TSource, bool>>
        (Expression.Equal(propertyReference, constantReference),
        new[] { pe }).Compile();
}

I am trying to create a list of expressions, then query my datasource with the final concatenated/compiled expression.

I have tried to use Expression.Block but the concept is a bit difficult for me to grasp. I have also seen Expression.Loop but am not sure if it's what I need to use here.

Ideally, I would be able to do something like this:

var filters = request.Filter.Filters;

IQueryable<MyDTO> myDataSource = context.MyDataSource;

var expressions = null;

foreach (var filter in filters)
{

    expressions.Add(SimpleExpression<MyDTO>(filter.Name, filter.Value));

}

return myDataSource.Where(expressions);

Any ideas on how to do something like this?


Solution

  • You're over-thinking things. You don't need to combine your expressions at all. The only complicated part is implementing SimpleComparison, but you've done that already. Well, mostly. You should be returning Expression<Func<...>>, not Func<...>, so it should be

    public Expression<Func<TSource, bool>> SimpleComparison<TSource>(string property, object value)
    {
        // ...
        return Expression.Lambda<Func<TSource, bool>>
            (Expression.Equal(propertyReference, constantReference),
            new[] { pe });
    }
    

    Once you have that, you can chain the filters by calling Where repeatedly, like so:

    var filters = request.Filter.Filters;
    IQueryable<MyDTO> query = context.MyDataSource;
    foreach (var filter in filters)
        query = query.Where(SimpleComparison<MyDTO>(filter.Name, filter.Value));
    return query;