LINQ Expression<Func<T, bool>> equavalent of .Contains()
Asked Answered
L

2

9

Has anybody got an idea of how to create a .Contains(string) function using Linq Expressions, or even create a predicate to accomplish this

public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
      Expression<Func<T, bool>> expr2)
{
    var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
    return Expression.Lambda<Func<T, bool>>
               (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}

Something simular to this would be ideal?

Lackluster answered 17/3, 2010 at 9:9 Comment(2)
Start excepting some answers first, such as this one #1648770 and this #2332427.Rhizopod
Here another dup: #1271283Dysthymia
C
5
public static Expression<Func<string, bool>> StringContains(string subString)
{
    MethodInfo contains = typeof(string).GetMethod("Contains");
    ParameterExpression param = Expression.Parameter(typeof(string), "s");
    var call = Expression.Call(param, contains, Expression.Constant(subString, typeof(string)));
    return Expression.Lambda<Func<string, bool>>(call, param);
}

...

// s => s.Contains("hello")
Expression<Func<string, bool>> predicate = StringContains("hello");

Looking at this many years later, I suddenly realize there's a much simpler approach for this specific example:

Expression<Func<string, bool>> predicate = s => s.Contains("hello");
Caliber answered 17/3, 2010 at 9:29 Comment(2)
Just to give some clarity, this solution mentioned above won't work if you use it directly, I only used some of the content like the MethodInfo and ParameterExpression.Lackluster
The return does not work, because the Expression.Call want to give back MethodCallExpression type. You should change to this: var call = Expression.Call(param, contains, Expression.Constant(subString, typeof(string))); return Expression.Lambda<Func<string, bool>>(call, param);Hoehne
C
4

I use something similiar, where I add filters to a query.

public static Expression<Func<TypeOfParent, bool>> PropertyStartsWith<TypeOfParent, TypeOfPropery>(PropertyInfo property, TypeOfPropery value)
{
     var parent = Expression.Parameter(typeof(TypeOfParent));
     MethodInfo method = typeof(string).GetMethod("StartsWith",new Type[] { typeof(TypeOfPropery) });
     var expressionBody = Expression.Call(Expression.Property(parent, property), method, Expression.Constant(value));
     return Expression.Lambda<Func<TypeOfParent, bool>>(expressionBody, parent);
}

Usage, to apply filter against a property whose name matches Key, and using supplied value, Value.

public static IQueryable<T> ApplyParameters<T>(this IQueryable<T> query, List<GridParameter> gridParameters)
{

   // Foreach Parameter in List
   // If Filter Operation is StartsWith
    var propertyInfo = typeof(T).GetProperty(parameter.Key);
    query = query.Where(PropertyStartsWith<T, string>(propertyInfo, parameter.Value));
}

And yes, this method works with contains:

        public static Expression<Func<TypeOfParent, bool>> PropertyContains<TypeOfParent, TypeOfPropery>(PropertyInfo property, TypeOfPropery value)
    {
        var parent = Expression.Parameter(typeof(TypeOfParent));
        MethodInfo method = typeof(string).GetMethod("Contains", new Type[] { typeof(TypeOfPropery) });
        var expressionBody = Expression.Call(Expression.Property(parent, property), method, Expression.Constant(value));
        return Expression.Lambda<Func<TypeOfParent, bool>>(expressionBody, parent);
    }

By having those 2 examples, you can more easily understand how we can call various different methods by name.

Cash answered 24/11, 2015 at 17:55 Comment(1)
In this line MethodInfo method = typeof(string).GetMethod("Contains", new Type[] { typeof(TypeOfPropery) }); you are assuming that the typeof(TypeOfPropery) is of type string because Contains only valid for string, so you can just use MethodInfo method = typeof(string).GetMethod("Contains", new Type[] { typeof(string) }); instead.Amplification

© 2022 - 2024 — McMap. All rights reserved.