I have a situation where I need to dynamically create a list of filters to apply to a list of objects. These objects can be anything that implements an interface that contains all the properties that need to be filtered.
public interface IStuff { bool SuitableForSomething { get; set; } bool SuitableForSomethingElse { get; set; } } public class SomeStuff : IStuff { ... } public class SomeOtherStuff : IStuff { ... }
I have a list of criteria defined like this ...
public List<Expression<Func<IStuff, bool>>> Criteria { get; private set; }
and add such criteria ...
Criteria.Add(x => x.SuitableForSomething); Criteria.Add(x => x.SuitableForSomethingElse);
Then I apply the criteria to my query, for example ...
var stuff= _stuffCache .GetAll() .AsQueryable() .ApplyCriteria(Criteria);
which uses the following extension method ...
public static IQueryable<T> ApplyCriteria<T>(this IQueryable<T> stuff, List<Expression<Func<IStuff, bool>>> criteria) where T : IStuff { foreach (var expression in criteria) { stuff = Queryable.Where(stuff, expression); } return stuff; }
The compiler tells me ...
cannot convert from 'System.Linq.Expressions.Expression<System.Func<IStuff,bool>>' to 'System.Linq.Expressions.Expression<System.Func<T,int,bool>>'
When I click on the red line under the error in the IDE, it says that it cannot resolve the method between
IQueryable<IStuff> Where<IStuff>(this IQueryable<IStuff>, Expression<Func<IStuff, bool>>) in class Queryable and IQueryable<T> Where<T>(this IQueryable<T>, Expression<Func<T,int,bool>>) in class Queryable
If I try to apply the expression to Expression<Func<T, bool>>
, which should work, since T is limited to implement the IStuff interface. I get
Cannot cast expression of type 'Expression<Func<IStuff, bool>>' to type 'Expression<Func<T, bool>>'
EDIT Thanks to Raphaël's answer, I fixed the extension method and ended up finding the real problem that I encountered when I called the code. Easily fixed by adding .Cast<SomeStuff>()
after calling ApplyCriteria
.
Before
var stuff= _stuffCache .GetAll() .AsQueryable() .ApplyCriteria(Criteria);
After
var stuff= _stuffCache .GetAll() .AsQueryable() .ApplyCriteria(Criteria) .Cast<SomeStuff>();