为List.Any生成表达式树(v => v.Contains(Book.Title.ToString()))

时间:2016-04-06 18:02:46

标签: c# lambda expression expression-trees

正如标题所说,如果字符串列表中的任何项目与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.IEnumerable 1 [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);
    }

1 个答案:

答案 0 :(得分:3)

最终工作代码:

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

有关问题的更深入解释。请参阅原帖中的我的编辑。