C # general restriction not working as expected

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>(); 
+6
source share
1 answer

change the second parameter type to List<Expression<Func<T,bool>>> (T instead of IStuff)

 public static IQueryable<T> ApplyCriteria<T>(this IQueryable<T> stuff, List<Expression<Func<T, bool>>> criteria) where T : IStuff { foreach (var expression in criteria) { stuff = Queryable.Where(stuff, expression); //or stuff = stuff.Where(expression), as Where is an Extension method; } return stuff; } 

and your method can be (thanks resharper), rewritten to

 public static IQueryable<T> ApplyCriteria<T>(this IQueryable<T> stuff, List<Expression<Func<T, bool>>> criteria) where T : IStuff { return criteria.Aggregate(stuff, (current, expression) => current.Where(expression)); } 
+7
source

Source: https://habr.com/ru/post/918086/


All Articles