I have a list of strings string[] searchValues
and a LINQ expression
queryable.Where(c => c.Tags != null && searchValues.All(s => c.Tags.Contains(s)));
where .Tags
is a List<string>
I want to rewrite it as an expression (filters and sorting orders are coming from UI as strings, and I wanted to create a generic method to convert it to expressions)
So far I've written this, but it's incorrect.
private static Expression GetFilterExpressionIListString2(MemberExpression memberExp, string[] values)
{
var anyMethod = typeof(Enumerable).GetMethods().First(m => m.Name == "Any" && m.GetParameters().Length == 2);
var specificAnyMethod = anyMethod.MakeGenericMethod(typeof(string));
Expression<Func<List<string>, bool>> lambda = s => values.All(v => s.Contains(v));
var anyExp = Expression.Call(specificAnyMethod, memberExp, lambda);
var notNullExp = Expression.NotEqual(memberExp, Expression.Constant(null));
var andExp = Expression.AndAlso(notNullExp, anyExp);
return andExp;
}
// an example of a dynamicly built tree that works
// .Tags.Wheere(x => x != null && values.Contains(x.Title))
private static Expression GetFilterExpressionString(MemberExpression memberExp, string[] values)
{
MethodInfo containsMethod = typeof(ICollection<string>).GetMethod("Contains", new[] { typeof(string) });
ConstantExpression constantExp = Expression.Constant(values);
MethodCallExpression containsExpression = Expression.Call(constantExp, containsMethod, memberExp);
return containsExpression;
}
The following function generates needed Lambda body:
private static Expression GetFilterExpressionIListString2(MemberExpression memberExpression, string[] values)
{
var param = Expression.Parameter(typeof(string), "s");
var valuesConstant = Expression.Constant(values);
var allLambda = Expression.Lambda<Func<string, bool>>(
Expression.Call(typeof(Enumerable), nameof(Enumerable.Contains), new[] { typeof(string) },
valuesConstant, param), param);
var filterExpression =
Expression.AndAlso(
Expression.NotEqual(memberExpression, Expression.Constant(null, memberExpression.Type)),
Expression.Call(typeof(Enumerable), nameof(Enumerable.All), new[] { typeof(string) }, valuesConstant, allLambda)
);
return filterExpression;
}