2

I am trying to create a reusable method using expressions that looks something like this:

Expression<Func<Order, bool>> CreateExpression(Expression<Func<Order, int>> parameter, FilterOperator operator, int value)

So I can use it like this:

IQueryable<Order> orders = db.Orders;

var filtered = orders.Where(CreateExpression(o => o.OrderID, FilterOperator.GreaterThan, 100));

I'm not sure how to write the method though. How can I write a method that will create this Expression for me?

I need to be able to do something like this:

if(operator == FilterOperator.GreaterThan)
   return m => m.OrderID > value;
else if(operator == FilterOperator.LessThan)
   return m => m.OrderID < value;

But I want to use the expression that is passed in instead of using OrderID directly. How can I do this?

5
  • 1
    Wouldn't it be easier to just do orders.Where(o => o.OrderID > 100)? If I knew why that didn't work for you, I could better make suggestions. Commented Nov 26, 2012 at 18:18
  • I don't want to do that because I want to apply the same logic to OrderID, OrderQuantity, etc. and also for GreaterThan, LessThan, GreaterThanEqualTo, EqualTo, NotEqualTo etc etc Commented Nov 26, 2012 at 18:21
  • 1
    But lambdas are so concise that you could simply create a new one with the condition you want. Commented Nov 26, 2012 at 18:22
  • So in each case, you want to write CreateExpression(x => x.SomeParameter, FilterOperator.GreaterThanEqualTo, 100) instead of x => x.SomeParameter >= 100? What are you trying to achieve? Commented Nov 26, 2012 at 18:23
  • 1
    The point is to not have a big if/else for each comparison operator and do: CreateExpression(x => x.Param, filterOperator, value) once instead of doing it 8 times in an if/else Commented Nov 26, 2012 at 18:28

1 Answer 1

5
static Expression<Func<T, bool>> CreateExpression<T>(Expression<Func<T, int>> parameter, FilterOperator @operator, int value)
{
    var argExpr = Expression.Parameter(typeof(T), "p");
    var paramExpr = Expression.Invoke(parameter, argExpr);
    var constExpr = Expression.Constant(value);
    Expression compExpr = null;
    switch(@operator)
    {
        case FilterOperator.GreaterThan:
            compExpr = Expression.GreaterThan(paramExpr, constExpr);
            break;
        case FilterOperator.LessThan:
            compExpr = Expression.LessThan(paramExpr, constExpr);
            break;
    }

    return Expression.Lambda<Func<T, bool>>(compExpr, argExpr);
}

If you can't use Invoke and your parameter expression is a member expression, then you can just re-create it using your new parameter:

static Expression<Func<T, bool>> CreateExpression<T>(Expression<Func<T, int>> parameter, FilterOperator @operator, int value)
{
    var memberExpr = (MemberExpression)parameter.Body;
    PropertyInfo property = (PropertyInfo)memberExpr.Member;

    var argExpr = Expression.Parameter(typeof(T), "p");
    var propertyExpr = Expression.Property(argExpr, property);
    var constExpr = Expression.Constant(value);

    Expression compExpr = null;
    switch(@operator)
    {
        case FilterOperator.GreaterThan:
            compExpr = Expression.GreaterThan(propertyExpr, constExpr);
            break;
        case FilterOperator.LessThan:
            compExpr = Expression.LessThan(propertyExpr, constExpr);
            break;
    }

    return Expression.Lambda<Func<T, bool>>(compExpr, argExpr);
}
Sign up to request clarification or add additional context in comments.

3 Comments

I am using this in an IQueryable and am getting an error that Invoke is not supported. Is there an alternative to this?
@Dismissile - If your parameter expression is a property accessor, then yes. I'll update in a minute...
@Dismissile - I've updated the answer to remove the call to Invoke.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.