2

I'm trying to build a predicate builder which return a predicate that checks whether a list of ints contains another list of ints. So far I have this

public static Expression<Func<T, bool>> DynamicIntContains<T, TProperty>(string property, IEnumerable<TProperty> items)
{
    var pe = Expression.Parameter(typeof(T));
    var me = Expression.Property(pe, property);
    var ce = Expression.Constant(items);
    var call = Expression.Call(typeof(List<int>), typeof(List<int>).GetMethod("Contains").Name, new[] { typeof(int) }, ce, me);
    return Expression.Lambda<Func<T, bool>>(call, pe);
}

T is the search object which contains a list of Ids as one of it's properties. TProperty is a list of ints and property is the name of the list on the property.The error I am getting is

Additional information: No method 'Contains' exists on type 'System.Collections.Generic.List`1[System.Int32]'.

Is this because I am calling it from a static method? Or am I trying to access the method on the typeof(List) incorrectly? Thanks.

Dave Swersky
  • 34,502
  • 9
  • 78
  • 118
Dan
  • 1,450
  • 1
  • 17
  • 34
  • possible duplicate of [How do I use LINQ Contains(string\[\]) instead of Contains(string)](http://stackoverflow.com/questions/194930/how-do-i-use-linq-containsstring-instead-of-containsstring) – GSerg Oct 30 '14 at 17:48
  • It isn't related to that question at all. – Dan Oct 30 '14 at 17:54
  • How about this one, @Dan http://stackoverflow.com/questions/16347794/how-to-build-an-ienumerableint-contains-expression – Darek Oct 30 '14 at 18:53
  • That is more related, but still gives the exception "Additional information: No generic method 'Contains' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic." – Dan Oct 31 '14 at 08:48
  • Is there any more information available? – Darek Oct 31 '14 at 14:41

2 Answers2

1

Here is the solution;

    public static Expression<Func<T, bool>> DynamicIntContains<T, TProperty>(string property, IEnumerable<TProperty> items, object source, PropertyInfo propertyInfo)
    {
        var pe = Expression.Parameter(typeof(T));
        var me = Expression.Property(pe, property.Singularise());
        var ce = Expression.Constant(propertyInfo.GetValue(source, null), typeof(List<int>));
        var convertExpression = Expression.Convert(me, typeof(int));
        var call = Expression.Call(ce, "Contains", new Type[] { }, convertExpression);
        return Expression.Lambda<Func<T, bool>>(call, pe);
    }

This works off the assumption that the list name is the plural of it's members. In Expression.Call I was passing a typeof(List), the correct method is to pass in Type[]. It seems to also be a requirement to convert the MemberExpression to a constant of a particular type. Thanks.

Dan
  • 1,450
  • 1
  • 17
  • 34
-2

Here you go:

class Program
{
    static void Main(string[] args)
    {
        var t1 = new List<int> {1, 3, 5};
        var t2 = new List<int> {1, 51};
        var s = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9};
        Console.WriteLine(s.Contains(t1));
        Console.WriteLine(s.Contains(t2));
    }

}

public static class Extensions
{
    public static bool Contains(this List<int> source, List<int> target)
    {
        return !target.Except(source).Any();
    }
}

And a Generic form:

public static bool Contains<T>(this List<T> source, List<T> target)
{
    return !target.Except(source).Any();
}

Even more generic:

public static bool Contains<T>(this IEnumerable<T> source, IEnumerable<T> target)
{
    return !target.Except(source).Any();
}
Darek
  • 4,687
  • 31
  • 47
  • This is only an option for LINQ to objects, while the question is very clearly building an expression for use in a query provider, to which it will be translated into SQL or some other non-C# querying mechanism. – Servy Oct 30 '14 at 18:30
  • Well, here is what I was thinking, @Servy, but I might be wrong. List does not have a method Contains which would accept a set. It only accepts a value of type T. I wonder if he will be able combine his code with mine, which provides for Contains with IEnumerable. I don't have much experience with expressions, yet, so it is a bit of shot in the dark. – Darek Oct 30 '14 at 18:45
  • This has nothing to do with the question, which is about building predicates. @Servy is exactly right. – Dan Oct 31 '14 at 08:30