将Linq表达式添加到表达式列表的方法

时间:2013-11-05 15:25:37

标签: c# linq lambda linq-expressions

我有一个Linq表达式列表,如:

List<Expression<Func<Customer, bool>>>

我需要从搜索页面添加一大堆谓词,例如:

x.Name.Contains(searchString)
x.Description.Contains(searchString)
...

我想创建一个方法,所以我不会得到大量的重复代码。带有签名的东西:

void AddCustomerPredicate(List<Expression<Func<Customer, bool>>> predicates, Expression<Func<Customer, string>> prop, string searchString);

我会用的是:

var predicates = new List<Expression<Func<Customer, bool>>>();
AddCustomerPredicate(predicates, x => x.Name, this.Name);
AddCustomerPredicate(predicates, x => x.Description, this.Description);
...

我已经简化了一点问题,但这就是它的要点。我没有用表达式树等做很多工作,所以我不确定如何实现这个方法?

**编辑**

我可能过分简化了这个问题。我知道如何添加到predicates.Add(x => x.Name.Contains(this.searchString))之类的列表中,但是在将每个搜索参数添加到列表之前,我想对每个搜索参数执行各种操作(例如,检查null或为空)。因此,我想在每个搜索参数上调用一个方法,如上所述,所以所有这些东西都可以包含在一个方法中。

2 个答案:

答案 0 :(得分:3)

您真正需要的是将Expression<Func<T, string>>翻译成Expression<Func<T, bool>>的方法:

public static Expression<Func<T, bool>> GetContainsExpression<T>(Expression<Func<T, string>> prop, string searchString)
{
    var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
    var someValue = Expression.Constant(searchString, typeof(string));
    var containsMethodExp = Expression.Call(prop.Body, method, someValue);

    return Expression.Lambda<Func<T, bool>>(containsMethodExp, prop.Parameters[0]);
}

这是受其他答案的启发:How do I create an expression tree to represent 'String.Contains(“term”)' in C#?

var predicates = new List<Expression<Func<Customer, bool>>>();
predicates.Add(GetContainsExpression((Customer x) => x.Name, this.Name));
predicates.Add(GetContainsExpression((Customer x) => x.Description, this.Description));

答案 1 :(得分:2)

我相信这会做你想要的,也会处理null属性值(因此调用Contains()不会抛出):

private static void AddCustomerPredicate(
    List<Expression<Func<Customer, bool>>> predicates,
    Expression<Func<Customer, string>> accessor,
    string searchString)
{
    var x = accessor.Parameters[0];
    var temp = Expression.Variable(typeof(string), "temp");

    var predicate = Expression.Lambda<Func<Customer, bool>>(
        Expression.Block(
            new[] { temp },
            Expression.Assign(
                temp,
                accessor.Body),
            Expression.AndAlso(
                Expression.IsFalse(
                    Expression.ReferenceEqual(
                        temp,
                        Expression.Default(typeof(string)))),
                Expression.Call(
                    temp,
                    "Contains",
                    Type.EmptyTypes,
                    Expression.Constant(searchString)))),
        x);

    predicates.Add(predicate);
}