为什么这个过滤器在List <t>上工作但不在IQueryable <t>上工作?</t> </t>

时间:2015-03-06 14:02:01

标签: c# linq extension-methods

我需要创建一个扩展方法,根据验证规则List<TSource>列表过滤集合List<<IRule>, bool>。 但是我收到错误VisitSubQueryExpression method is not implemented而我看不到/找不到问题的原因。

这是我的扩展方法:

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界面:

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

扩展方法调用示例

//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
                       }
                   });

此示例应过滤listToValidate列表并删除所有SampleType实例,其Name属性为Null或Whitespace

我的扩展方法有什么问题?这个“VisitSubQueryExpression方法未实现”错误是什么意思?

如果我将其更改为List<TSource>而不是IQueryable<TSource>的扩展方法 - 它可以正常工作!为什么?

this IQueryable<TSource>替换为this List<TSource>,它有效,为什么? Where方法应该适用IQueryable<T>(继承自IEnumerable<T>),不应该吗?

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();
}

3 个答案:

答案 0 :(得分:2)

您的rule.RulePassed无法由您的IQueryable提供商翻译。

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;
}

答案 1 :(得分:1)

IQueryable<T>实现IEnumerable<T>但反之亦然。 List<T>未实现IQueryable<T>

这是List公开的接口列表: enter image description here

由于IQueryableIList都来自IEnumerable<T>,您可以使用它并在其上调用.AsQueryable来转换这两种情况。

答案 2 :(得分:0)

List<T>未实现IQueryable<T>,因此您无法在IQueryable<T>上调用其上的扩展方法。