ICollection <t>是非基于索引的,但TakeWhile()存在</t>

时间:2012-03-05 06:10:42

标签: c# .net collections

我正在尝试将T[]List<T>的用法替换为函数参数,并使用更合适的类型返回值,例如IEnumerable<T>ICollection<T>和{{1} }。

根据我的理解,

IList<T>优先于ICollection<T>,您只需要基本/简单的集合功能(例如枚举器和计数功能),因为它提供的限制最少。从这里读到我认为的一个主要区别是IList<T>不要求基础集合是ICollection<T>所在的基于索引的那个?

在切换IList<T>引用时,我需要替换List<T>来电,我很惊讶地发现List<T>.GetRange()扩展方法有一个过载支持基于索引的选择?! (msdn link)

我很困惑为什么这个方法存在于ICollection上,哪里没有基于此接口的索引?我是否误解了或者如果底层集合是例如Hashset或其他什么,这个方法如何实际工作?

3 个答案:

答案 0 :(得分:2)

与大多数LINQ一样,该方法位于IEnumerable<T>。只有将索引器传递给使用者的任何功能(例如TakeWhile)只需要在递增计数器时循环。某些API可能能够使用索引器优化,然后由他们来决定是否这样做,或者只使用IEnumerable<T>并简单地跳过(等)不需要的数据。 / p>

例如:

int i = 0;
foreach(var item in source) {
    if(!predicate(i++, item)) break;
    yield return item;
}

答案 1 :(得分:2)

索引可以在没有收集支持的情况下完成

int i = -1;

foreach(var item in collection)
{
   i++;
   // item is at index i;
}

答案 2 :(得分:0)

来自TakeWhile类的

System.Linq.Enumerable和其他扩展方法适用于实现IEnumerable<T>的所有类型。它们都遍历集合(使用foreach语句)并执行适当的操作。

以下是TakeWhile方法的实现,并进行了一些简化:

private static IEnumerable<TSource> TakeWhile<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    foreach (TSource item in source)
    {
        if (!predicate(item))
        {
            break;
        }
        yield return item;
    }
}

如您所见,它只是遍历集合,并评估谓词。对于几乎所有其他LINQ方法都是如此。使用任何其他集合时也会发生同样的情况,例如HashSet<T>