6

I have a situation where I need to dynamically build up a list of filters to apply to a list of objects. Those objects can be anything that implements an interface which contains all of the properties I need to filter on.

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

public List<Expression<Func<IStuff, bool>>> Criteria { get; private set; } 

and add criteria like so ...

Criteria.Add(x => x.SuitableForSomething);
Criteria.Add(x => x.SuitableForSomethingElse);

I then apply the criteria to my query like so ...

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 is telling me ...

cannot convert from
    'System.Linq.Expressions.Expression<System.Func<IStuff,bool>>'
to
    'System.Linq.Expressions.Expression<System.Func<T,int,bool>>'

When I hover over the red line under the error in the IDE it's saying it cannot resolve 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 casting the expression to Expression<Func<T, bool>>, which ought to work as T is constrained 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 eventually found the real problem I had, which was a casting problem when I was calling the code. Easily fixed by adding a .Cast<SomeStuff>() after the ApplyCriteria call.

Before

var stuff= _stuffCache
    .GetAll()
    .AsQueryable()
    .ApplyCriteria(Criteria);

After

var stuff= _stuffCache
    .GetAll()
    .AsQueryable()
    .ApplyCriteria(Criteria)
    .Cast<SomeStuff>();
4

1 回答 1

7

将第二个参数类型更改为List<Expression<Func<T,bool>>>(T 而不是 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;
}

并且您的方法可以(thx resharper)重写为

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));
        }
于 2012-06-14T11:29:37.593 回答