0

I am trying to create Contains clause to existing Func properties lists, but I don't know how to attach it to previously passed properties list.

public static List<Func<T, bool>> GetPropertyWhereClauses<T>(List<Func<T, object>> properties, string queryPhrase)
    {
        var whereClauses = new List<Func<T, bool>>();

        foreach (var property in properties)
        {
            /// how to add Contains to existing property Func<T, object> ?
            whereClauses.Add(property.Contains(queryPhrase));
        }

        return whereClauses;
    }

How to add that? I tried to use some Expression.Call but it doesn't take Func as parameter.

Staly
  • 85
  • 7

1 Answers1

1

If you just want to convert every Func<T, object> to Func<T, bool> if the first func return object casted to string contains the queryPhrase you can do this:

public static List<Func<T, bool>> GetPropertyWhereClauses<T>(List<Func<T, object>> funcs, string queryPhrase)
{
    var whereClauses = new List<Func<T, bool>>();
    foreach (var func in funcs)
    {
        whereClauses.Add(o => func(o).ToString().Contains(queryPhrase));
    }
    return whereClauses;
}

Or better with LINQ:

 public static List<Func<T, bool>> GetPropertyWhereClauses<T>(List<Func<T, object>> funcs, string queryPhrase)
{
    return funcs.Select(func => new Func<T, bool>(o => func(o).ToString().Contains(queryPhrase)).ToList();
}

If the reutrn object is actually a list and not a string you can check if queryPhrase is a part of the list in a similar way:

public static List<Func<T, bool>> GetPropertyWhereClauses<T>(List<Func<T, object>> funcs, string queryPhrase)
{
    return funcs.Select(func => new Func<T, bool>(o => ((List<string>)func(o)).Contains(queryPhrase)).ToList();
}

It is not the best idea to make your func return tpye an object if you can chage it to the real type you are expecting to, it will save you all the redundant casting.

YuvShap
  • 3,825
  • 2
  • 10
  • 24
  • It worked, but I have problem with the same for Linq Include.When I try to use `query = query.Include(x => include(x));` where include is `Func` I get an error: The Include path expression must refer to a navigation property defined on the type. – Staly Oct 23 '16 at 11:55
  • You can't use this approach with LINQ to Entities to filter the items in a Include method, please refer [this](http://stackoverflow.com/questions/25629022/filtering-include-items-in-linq-and-entity-framework) question for alternatives. – YuvShap Oct 23 '16 at 11:59
  • I mean sth else. I want to add Include to my query not by string, but by Func. Cannot do that through object. – Staly Oct 23 '16 at 12:06
  • I didn't fully understand what is the problem and what you want to achieve, the best suggestion I have for you is to ask a new question with [a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). – YuvShap Oct 23 '16 at 12:10
  • `String.Contains` by default doesn't work for case difference, use an extension method to ignore the case. – Mrinal Kamboj Oct 23 '16 at 12:18
  • One more problem. When any of func is null in database, ToString() throws me an error. How to deal with it? – Staly Oct 24 '16 at 05:48
  • I did `whereClauses.Add(x => (property(x) ?? "").ToString().ToLower().Contains(queryPhrase.ToLower()));` - is that ok? – Staly Oct 24 '16 at 05:58
  • The problem is not that the func is null, the func result is. What you can do is to return false imedinately if the result is null, `property(x) != null ? property(x).ToString().ToLower().Contains(queryPhrase.ToLower()) : false` – YuvShap Oct 24 '16 at 07:01
  • I have one more problem. What about `Func` which is list of strings (example: `x => x.AspNetRoles.Select(y => y.Name)`). How can I loop through this list add make "Any" or sth like that? – Staly Oct 31 '16 at 09:10