简体   繁体   中英

Why does this filter work on a List<T> but not on an IQueryable<T>?

I need to create an extension method that will filter collection List<TSource> according to a list of validation rules List<<IRule>, bool> . But I get an error VisitSubQueryExpression method is not implemented and I don't see/can not find what is the problem cause.

This is my extension method:

public static List<TSource> ValidItems<TSource>(this IQueryable<TSource> source, 
                                  List<IValidationRule<TSource>> validationRules)
{
     return source.Where(testableItem => 
            validationRules.All(rule => rule.RulePassed(testableItem))).ToList();
}

IRule interface:

public interface IValidationRule<T> //with implementation class ValidationRule<T>
{
    Func<T, bool> RulePassed { get; set; }
    //... +other code
}

Sample of extension method call

//initialization of List<SampleType> listToValidate = ... 
var validItems = listToValidate.ValidItems(
                  new List<IValidationRule<SampleType>() {
                       new ValidationType<SampleType> {
                       RulePassed = (s) => string.IsNullOrWhiteSpace(SampleType.Name), 
                       //...initalize other ValidationType parameters
                       }
                   });

this sample should filter listToValidate list and remove all SampleType instances, with Name property that is Null or Whitespace

What is wrong with my extension method? What does this "VisitSubQueryExpression method is not implemented" error mean?

if I change it to be an extension method for List<TSource> not IQueryable<TSource> - it works! Why?

replacing this IQueryable<TSource> with this List<TSource> , it works, why? Where method should work on IQueryable<T> (inherits from IEnumerable<T> ), shouldn't it?

public static List<TSource> ValidItems<TSource>(this List<TSource> source, 
                                  List<IValidationRule<TSource>> validationRules)
{
     return source.Where(testableItem => 
            validationRules.All(rule => rule.RulePassed(testableItem))).ToList();
}

Your rule.RulePassed cannot be translated by your IQueryable provider.

public static List<TSource> ValidItems<TSource>(this IQueryable<TSource> source, 
                              List<IValidationRule<TSource>> validationRules)
{
    var result = new List<TSource>();
    foreach (var testableItem in source)
    {
        if (validationRules.All(rule => rule.RulePassed(testableItem))
        {
            result.Add(testableItem);
        }
    }
    return result;
}

IQueryable<T> implements IEnumerable<T> but not vice versa. And List<T> doesn't implement IQueryable<T> .

This is the list of interfaces exposed by List: 在此处输入图片说明

Since both IQueryable and IList inherit from IEnumerable<T> you could use that and call .AsQueryable on it to convert both cases.

List<T>不实现IQueryable<T> ,因此您不能在IQueryable<T>上定义的扩展方法上调用它。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM