Search code examples
c#expression-treespredicate

How to filter objects based on type-imposed predicate collections?


I have a situation in which i would like to filter objects based on collections of predicates imposed on their particular types: Could this be done via precompiled ExpressionTrees ?

class A
{
   public int Value {get;set;}
}
class B
{
  public string Name {get;set;}
  public bool IsMajor{get;set;}
}


Dictionary<Type,IEnumerable<Predicate<[object casted to type]>> typePredicateMap=new Dictionary<Type,Predicate<[object casted to type]>>{
   {typeof(A),new List<Predicate<[object casted to A]> { x=>x.Value >100,x=>x.Value<200 }},
   {typeof(B),new List<Predicate<[object casted to B]> { x=>x.Name!="johhnny",x=>x.IsMajor==true }}
}

I said above object casted to Type since i want my predicate to be based on that particular type..

public static bool MeetsCriteria(object data)
{
    Type type=typeof(data);
    IEnumerable<Predicate<object>predicates=typePredicateMap[type];
    bool isValid=true;
    foreach(var predicate in predicates)
    {
        isValid&=predicate(data);  //
    }
    return isValid;
}

Solution

  • The main issue is that since we want to dynamically choose the predicates to call, they need to be of type Predicate<object>, since the type we are invoking them on is object. Due to the fact that Predicate<T> is contravariant (defined as Predicate<in T>), that means that we can specify a less-derived type for T where a more derived type is expected.

    In practice that means that if you had a class A and class B : A, you could use a Predicate<A> as a Predicate<B> or a Predicate<object> as Predicate<A>, but you can't do Predicate<A> where Predicate<object> is expected. This means that your predicates will have to be of type Predicate<object> and cast the object parameter to the right type manually.

    I guess that was a long-winded way of saying you just have to use Predicate<object> everywhere, or find some way to constrain your input objects. Does your MeetsCriteria method really need to handle every object which might ever exist?

    I don't believe what your are asking for is possible to solve with expression trees since the problem with types will still be present, but hey, maybe someone will prove me wrong.