2

Ok so here's the problem I am creating an expression dynamically to execute against the database, that works fine. the problem appears when I add another expression using Expression.AndAlso, the expressions combine fine but the parameters don't work, my code is below.

Expression<Func<Invoice, bool>> condition = null;

ParameterExpression[] param = new ParameterExpression[sessionModel.FilterChildren.Count];

foreach (var filter in sessionModel.FilterChildren) {

   param[i] = Expression.Parameter(typeof(Invoice), filter.SysName);

   Type type = Type.GetType(filter.Type);

   if (i == 0)
     condition =
         Expression.Lambda<Func<Invoice, bool>>(
             Expression.Equal(
             Expression.Property(param[i], filter.SysName),
             Expression.Constant(filter.Value, type)
            ),
              param[i]);
    else {
      var newCond = Expression.Lambda<Func<Invoice, bool>>(
         Expression.Equal(
             Expression.Property(param[i], filter.SysName),
             Expression.Constant(filter.Value, type)
            ),
              param[i]);

       var test = Expression.AndAlso(condition.Body, newCond.Body);

       condition = Expression.Lambda<Func<Invoice, bool>>(test, param);
    }
    i++;
  }

it throws an error

Incorrect number of parameters supplied for lambda declaration

there are different parameters for each expression that will be added.

any ideas where i am going wrong?

Thanks

8
  • 1
    Do you assign a value to condition before if block? Commented Aug 12, 2016 at 10:44
  • I've updated my question to show what is called just before :) Commented Aug 12, 2016 at 10:47
  • Well, I'd expect a NullReferenceException as you do Expression<Func<Invoice, bool>> condition = null; and then if if block is not triggered var test = Expression.AndAlso(condition.Body, newCond.Body); but I guess i is initially 0 as well, so that's not the case. Which line throws the exception? AndAlso part seems to be Ok to my inexperienced eyes tbh. Commented Aug 12, 2016 at 11:05
  • Shortly - you should use one and the same parameter. Commented Aug 12, 2016 at 11:07
  • the issue is on the line condition = Expression.Lambda<Func<Invoice, bool>>(test, param); the and also seems to work fine Commented Aug 12, 2016 at 11:07

1 Answer 1

4

how to use multiple parameters when combining expressions using Expression.Lambda

You shouldn't be using multiple parameters. The lambda expression

Expression<Func<Invoice, bool>> condition

implies single parameter of type Invoice.

To fix the issue, replace

ParameterExpression[] param = new ParameterExpression[sessionModel.FilterChildren.Count];

with

var param = Expression.Parameter(typeof(Invoice), "invoice");

and in the rest of the code, replace param[i] with param.

P.S. There is no real need to create lambda expressions for each filter because as you can see, when combining them you use only the Body. The whole procedure can be trimmed down to something like this:

Expression<Func<Invoice, bool>> condition = null;
if (sessionModel.FilterChildren.Any())
{
    var parameter = Expression.Parameter(typeof(Invoice), "invoice");
    var body = sessionModel.FilterChildren
        .Select(filter => Expression.Equal(
            Expression.Property(parameter, filter.SysName),
            Expression.Constant(filter.Value, Type.GetType(filter.Type))))
        .Aggregate(Expression.AndAlso);
    condition = Expression.Lambda<Func<Invoice, bool>>(body, parameter);
}
Sign up to request clarification or add additional context in comments.

4 Comments

Just trying to learn, so it might sound stupid, but what's the reason behind this? Isn't param[i] also a ParameterExpression as expected in Expression.Lambda ?
Yes, it is. But they are different objects and not considered to be one and the same. Even the names doesn't matter. So the real trick is to use one and the same parameter expression instance.
makes sense :) Thanks for that...Legend
Just added a simplified way of doing the same (for learning purposes :)

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.