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?

Mike Two
  • 44,935
  • 9
  • 80
  • 96
BK.
  • 365
  • 4
  • 13
  • 2
    Start excepting some answers first, such as this one http://stackoverflow.com/questions/1648270/how-to-determine-what-happens-behind-the-scene-in-net/1648306#1648306 and this http://stackoverflow.com/questions/2331927/linq-to-xml-replace-child-nodes-but-keep-state/2332087#2332087. – Steven Mar 17 '10 at 09:27
  • Here another dup: http://stackoverflow.com/questions/1270783/how-to-combine-two-expressions-result-exp1exp2 – Kamarey Mar 17 '10 at 09:38

2 Answers2

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");
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • 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. – BK. Mar 18 '10 at 06:57
  • 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>(call, param); – Bence Végert Oct 18 '18 at 12:42
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.

Greg
  • 2,410
  • 21
  • 26
  • 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. – Shahar Shokrani Oct 01 '20 at 22:34