Question

I have a list of Linq expressions like:

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

I need to add a whole bunch of predicates from a search page, like:

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

I want to create a method so I don't end up with a mass of duplicated code. Something with a signature like:

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

Which I would use like:

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

I've simplified the problem a bit, but that is the gist of it. I haven't done much work with expression trees and the like, so I'm not sure how to implement this method?

**EDIT**

I might have over simplified the problem too much. I know how to add to the list like predicates.Add(x => x.Name.Contains(this.searchString)), but I have various things I want to do on each search parameter before adding it to the list (e.g. check for null or empty). I therefore want to call a method on each search parameter as above, so all of that stuff can be contained in a single method.

Était-ce utile?

La solution

What you really need is to have a method for translated Expression<Func<T, string>> to 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]);
}

This is inspired by this other answer : 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));

Autres conseils

I believe this will do what you want, and will also handle null property values (so calling Contains() does not throw):

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);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top