ICollection 不是基于索引的,但 TakeWhile() 存在

本文关键字:存在 TakeWhile 索引 ICollection 于索引 | 更新日期: 2023-09-27 18:26:35

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

ICollection<T>根据我的理解,建议您只需要基本/简单的收集功能(例如枚举器和计数功能(IList<T>,因为它提供了最少的限制。从阅读这里,我认为主要区别之一是ICollection<T>不要求基础集合基于索引,而IList<T>

在切换我的List<T>引用时,我需要替换一个List<T>.GetRange()调用,我非常惊讶地发现ICollection<T>.TakeWhile()扩展方法具有重载支持基于索引的选择?!(MSDN 链接(

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

ICollection<T> 不是基于索引的,但 TakeWhile() 存在

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

例如:

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

可以在没有集合支持的情况下完成

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

System.Linq.Enumerable类中的TakeWhile和其他扩展方法适用于所有实现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> .