As the title says, I'm trying to generate an Expression tree for cheking if any item in a list of strings matches a string of a Book object.
So far I've got this:
private static Expression<Func<Books, bool>> GenerateListContainsLikeExpression(string propertyName, List<string> values)
{
var parameter = Expression.Parameter(typeof(Books), "b");
var listParameter = Expression.Parameter(typeof(string), "v");
var property = Expression.Property(parameter, propertyName);
var anyMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).First(m => m.Name == "Any" && m.GetParameters().Count() == 2).MakeGenericMethod(typeof(string));
var toStringMethod = typeof(object).GetMethod("ToString");
var containsMethod = typeof(string).GetMethod("Contains");
var objectString = Expression.Call(property, toStringMethod);
var lambda = Expression.Call(listParameter, containsMethod, objectString);
var func = Expression.Lambda<Func<List<string>, bool>>(lambda, parameter);
var comparison = Expression.Call(anyMethod, Expression.Constant(values), func);
return Expression.Lambda<Func<Books, bool>>(comparison, parameter);
}
But I'm getting this error:
Expression of type 'System.Boolean' cannot be used for parameter of type 'System.Func
2[System.String,System.Boolean]' of method 'Boolean Any[String](System.Collections.Generic.IEnumerable
1[System.String], System.Func`2[System.String,System.Boolean])'
At this line:
var comparison = Expression.Call(anyMethod, Expression.Constant(values), lambda);
I feel like I just need the last little bit.
Thanks in advance :-)
EDIT: For clarification. I'll explain a little more detailed what I needed.
I needed to categorize books based on some of the books properties. In this specific case, I pass a list of strings to the function. I needed to check if any of these strings was contained in any books title.
So first of all, the lambda I thought I needed was wrong to begin with. This is the lambda that I actually needed: b => values.Any(v => b.Title.ToString().Contains(v))
And here is the final code I ended up with:
private static Expression<Func<Books, bool>> GenerateListContainsLikeExpression(string propertyName, List<string> values)
{
var parameter = Expression.Parameter(typeof(Books), "b");
var listParameter = Expression.Parameter(typeof(string), "v");
var property = Expression.Property(parameter, propertyName);
var anyMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).First(m => m.Name == "Any" && m.GetParameters().Count() == 2).MakeGenericMethod(typeof(string));
var toStringMethod = typeof(object).GetMethod("ToString");
var containsMethod = typeof(string).GetMethod("Contains");
var objectString = Expression.Call(property, toStringMethod);
var lambda = Expression.Call(objectString, containsMethod, listParameter);
var func = Expression.Lambda<Func<string, bool>>(lambda, listParameter);
var comparison = Expression.Call(anyMethod, Expression.Constant(values), func);
return Expression.Lambda<Func<Books, bool>>(comparison, parameter);
}
Final working code:
private static Expression<Func<Books, bool>> GenerateListContainsLikeExpression(string propertyName, List<string> values)
{
var parameter = Expression.Parameter(typeof(Books), "b");
var listParameter = Expression.Parameter(typeof(string), "v");
var property = Expression.Property(parameter, propertyName);
var anyMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).First(m => m.Name == "Any" && m.GetParameters().Count() == 2).MakeGenericMethod(typeof(string));
var toStringMethod = typeof(object).GetMethod("ToString");
var containsMethod = typeof(string).GetMethod("Contains");
var objectString = Expression.Call(property, toStringMethod);
var lambda = Expression.Call(objectString, containsMethod, listParameter);
var func = Expression.Lambda<Func<string, bool>>(lambda, listParameter);
var comparison = Expression.Call(anyMethod, Expression.Constant(values), func);
return Expression.Lambda<Func<Books, bool>>(comparison, parameter);
}
For a more in depth explanation of the problem. See my edit in the original post.