【发布时间】:2016-04-06 18:02:46
【问题描述】:
正如标题所说,我正在尝试生成一个表达式树,用于检查字符串列表中的任何项目是否与 Book 对象的字符串匹配。
到目前为止,我得到了这个:
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);
}
但是我收到了这个错误:
“System.Boolean”类型的表达式不能用于“System.Func
2[System.String,System.Boolean]' of method 'Boolean Any[String](System.Collections.Generic.IEnumerable1[System.String], System.Func`2[System.String,System.Boolean])”类型的参数
在这一行:
var comparison = Expression.Call(anyMethod, Expression.Constant(values), lambda);
我觉得我只需要最后一点。
提前致谢:-)
编辑:澄清。我会更详细地解释我需要什么。
我需要根据一些书籍属性对书籍进行分类。在这种特定情况下,我将字符串列表传递给函数。我需要检查这些字符串中的任何一个是否包含在任何书名中。
首先,我认为我需要的 lambda 是错误的。这是我真正需要的 lambda:b => values.Any(v => b.Title.ToString().Contains(v))
这是我最终得到的代码:
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);
}
【问题讨论】:
-
你的函数可能不是你想象的那样,而且可能搞砸了。 Any 是一种扩展方法,因此您必须在您的表达式中调用静态方法。列表应该是书籍列表吗?看起来是这样,但您似乎将 Any func 的参数视为列表本身,而不是列表中的一本书。一切看起来都错了……我认为有一个 lambda => 表达式转换器可以用来学习东西是如何工作的……让我看看吧。
-
是的,我认为您可以直接转到
Expression<Func<TInput,bool>> expr = x => x.Any(v => v.Contains(Book.Title.ToString()));,然后检查快速观察窗口中的表达式,看看它是如何构造的。同样,我不知道您的TInput来自您标题中的 lambda。 -
我已经编辑了帖子,所以你可以看到完整的方法。
-
lambda 仍然不正确。你想要
b => values.Any(v => b.Any(x => x.Title.ToString().Contains(v))),其中values将是字符串值的常量枚举。您的方法返回一个以Books作为参数的函数。调查一下。 -
@Will 是的,Books 确实有一个名为 Title 的属性。而我现在才明白你为什么感到困惑。我们的数据库表称为 Books,因此 Entity Framework 调用模型 Books。我现在已经习惯了,因此对这个事实视而不见:-)
标签: c# lambda expression expression-trees