Search code examples
c#genericsexpression-trees

How do I build an expression to apply a Where clause generically to an IQueryable<T>?


I have a class called TestObject with a Name parameter.

I create a list and add 2 of these. I want to create a generic Where() clause method for any IQueryable<T>.

I've been playing around with Expressions but I don't really know what I'm doing.

I created this method with some hardcoded values for testing, I want it to do collection.Where(c => c.Name == "Boris"):

public static IQueryable<T> Apply<T>(IQueryable<T> collection)
{
    var parameterName = "Name";
    var searchValue = "Boris";

    var selectorParameter = Expression.Parameter(typeof(T), parameterName);
    var searchTermExpression = Expression.Constant(searchValue);    
    var checkEqualsExpression = Expression.Call(selectorParameter, typeof(string).GetMethod("Equals"), searchTermExpression);

var methodCallExpression = Expression.Call(typeof(Queryable),
    "Where",
    new Type[] { collection.ElementType },
    collection.Expression,
    Expression.Lambda<Func<T, bool>>(checkEqualsExpression , ?????));

    return collection.Provider.CreateQuery<T>(methodCallExpression);
}

I'm not sure what goes in ????? or even if this is correct. Can anyone advise?


Solution

  • Here is an example of how to do it, with comments, it should clarify what you are doing wrong.

    public static IQueryable<T> Apply<T>(IQueryable<T> collection) {
        var propertyName = "Name";
        var searchValue = "Boris";
        // we have parameter "c"
        var selectorParameter = Expression.Parameter(typeof(T), "c");
        // constant "Boris"
        var searchTermExpression = Expression.Constant(searchValue);
        // "c.Name"
        var selector = Expression.PropertyOrField(selectorParameter, propertyName);
        // "c.Name == "Boris"
        var equal = Expression.Equal(selector, searchTermExpression);
        // c => c.Name == "Boris"
        var where = Expression.Lambda<Func<T, bool>>(equal, selectorParameter);
        return collection.Where(where);
    }