Search code examples
c#linqreflectionpredicates

Create a predicate builder for (x => listOfInts.Contains(x.ListOfIntsToCheck))


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.


Solution

  • 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.