Harish Ninge Gowda
Harish Ninge Gowda

Reputation: 441

Incorrect number of parameters supplied for lambda declaration while building expression from object

I have created a method which converts object to expression.

private Expression<Func<TDto, bool>> GetObjectAsExpression<TSearchDto, TDto>(TSearchDto searchDto)
    where TSearchDto : class where TDto : class
{
    List<ParameterExpression> parameterExpressions = new List<ParameterExpression>();
    Expression predicateBody = default(Expression);
    int nodeCount = 1;
    foreach (PropertyInfo property in searchDto.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        ParameterExpression parameterExpression =
            Expression.Parameter(typeof(TDto), $"node{nodeCount++}");
        parameterExpressions.Add(parameterExpression);

        Expression left = Expression.Property(parameterExpression, property.Name);
        Expression expression = Expression.Equal(left, Expression.Constant(property.GetValue(searchDto)));
        if (predicateBody == null)
        {
            predicateBody = expression;
        }
        else
        {
            predicateBody = Expression.And(predicateBody, expression);
        }
    }

    return Expression.Lambda<Func<TDto, bool>>(
        predicateBody,
        parameterExpressions
    );
}

Case 1: When I call this method with single property it works fine.

GetObjectAsExpression<object, TDto>(new { CaseNumber = "00100283900813414832"})

Case 2: When I call this method with 2 parameters it throws the error

GetObjectAsExpression<object, TDto>(new { CaseNumber = "00100283900813414832", WareHouse = "008" })

with the error

System.ArgumentException: 'Incorrect number of parameters supplied for lambda declaration'

I have also searched for a nuget package or the source that can accomplish this and more. Please suggest a solution or an existing package that does this and more.

Upvotes: 2

Views: 158

Answers (1)

AakashM
AakashM

Reputation: 63338

Not sure what your intention is with the whole nodeCount thing, but that's what's going wrong. There's only ever one parameter to the Func you are producing - a single TDto goes in and a bool comes out - so you shouldn't be passing a whole list of parameters to the predicate you build.

Also, for conciseness, if you start your predicate with true, you don't need that null check - you can just chain Ands.

Doing both gives:

private Expression<Func<TDto, bool>> GetObjectAsExpression<TSearchDto, TDto>(TSearchDto searchDto)
    where TSearchDto : class where TDto : class
{
    ParameterExpression singleParameterExpression = Expression.Parameter(typeof(TDto), "node");

    Expression predicateBody = Expression.Constant(true);
    foreach (PropertyInfo property in searchDto.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        Expression left = Expression.Property(singleParameterExpression, property.Name);
        Expression expression = Expression.Equal(left, Expression.Constant(property.GetValue(searchDto)));
        predicateBody = Expression.And(predicateBody, expression);
    }

    return Expression.Lambda<Func<TDto, bool>>(
        predicateBody,
        singleParameterExpression
    );
}

which I think gives the result you want.

Upvotes: 1

Related Questions