Reputation: 441
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
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 And
s.
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