【问题标题】:Generating Expression Tree for List.Any(v => v.Contains(Book.Title.ToString()))为 List.Any(v => v.Contains(Book.Title.ToString())) 生成表达式树
【发布时间】: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.Func2[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 =&gt; values.Any(v =&gt; 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&lt;Func&lt;TInput,bool&gt;&gt; expr = x =&gt; x.Any(v =&gt; v.Contains(Book.Title.ToString()));,然后检查快速观察窗口中的表达式,看看它是如何构造的。同样,我不知道您的 TInput 来自您标题中的 lambda。
  • 我已经编辑了帖子,所以你可以看到完整的方法。
  • lambda 仍然不正确。你想要b =&gt; values.Any(v =&gt; b.Any(x =&gt; x.Title.ToString().Contains(v))),其中values 将是字符串值的常量枚举。您的方法返回一个以Books 作为参数的函数。调查一下。
  • @Will 是的,Books 确实有一个名为 Title 的属性。而我现在才明白你为什么感到困惑。我们的数据库表称为 Books,因此 Entity Framework 调用模型 Books。我现在已经习惯了,因此对这个事实视而不见:-)

标签: c# lambda expression expression-trees


【解决方案1】:

最终工作代码:

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);
}

对于问题的更深入的解释。在原始帖子中查看我的编辑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多