IEnumerable上的First()和Last()真的是第一个和最后一个吗<>?



我最近意识到,你不应该对IEnumerable的实现做任何假设(例如,你不能假设当你在foreach循环中对来自IEnumerable的一个对象进行更改时,在循环之后(甚至在每次迭代之后)可以在IEnumerable中找到更改的对象。

因此,在重新检查了我对IEnumerable的假设之后,我得出结论,实际上您唯一可以确定的是,它允许您遍历集合的所有元素,其中集合(不是ICollection本身)可以是任何东西。

另一个我认为我不能做的假设是底层集合的顺序是特定的。理论上,每次循环时,你都可以以不同的顺序得到这些元素。

现在回到我最初的问题,考虑到上面的问题,First()Last()每次都可以返回不同的项(理论上看IEnumerable是什么)?

Exra信息:当然,这通常是没问题的,因为IEnumerable是由有序的东西实现的。但是如果IEnumerable调用webservice来获取它的元素呢?

背景信息:我之所以这么想,是因为我想对foreach循环中的第一个和最后一个元素做一些具体的操作。所以我选中了if(currentElement == Enumerable.Last())

First()获得一个枚举数并返回它找到的第一个值。Last()通常遍历整个集合,并在到达枚举结束之前返回元素1。没错,这就是你所知道的一切。具体来说,collection可以是无限的,然后Last()将永远不会返回。

Jon Skeet有一系列非常有用的关于LINQ操作符的文章-参见Edulinq。他描述了每一个LINQ算子,并详细讨论了所有的想法和假设。

我选中了if(currentElement == Enumerable.Last())

Last()实际上是最后一个,但是调用它枚举你的Enumerable。它不是没有成本和副作用的。

这也给了你Last()的定义:迭代当前产生的最后一个元素。更改列表,您可能会有另一个Last()。

我可以想象,在多线程环境中,.First.Last可能被证明是不确定的,特别是如果您对并发性不小心的话。

正如其他人提到的,如果您不知道底层的可枚举对象是什么,那么您可能不应该假设First()或Last()的行为如您所期望的那样。然而,如果你已经打算在IEnumerable上循环,并希望获得enumerable当前状态的"快照",那么你就可以保证First()和Last()的行为符合预期。我会像这样将IEnumerable转换为列表(或数组),然后您应该不会有任何问题:

var list = enumerable.ToList();
foreach(var currentItem in list)
{
    if(currentItem == list.First())
    {
        //Do something with the first item
    }
    else if(currentItem == list.Last())
    {
        //Do something with the last item
    }
    //Do something for all items
}

您可以使用Enumerable。OrderBy方法,以确保可枚举对象按照所需的标准排序,并获得您真正想要的第一个或最后一个项。

Enumerable.first()和Enumerable.last()实际上是真正的第一个和最后一个元素。在这种情况下,您必须指定您认为应该是第一个和最后一个元素。例如,这很大程度上取决于如何对Enumerable中的元素进行排序,以及在排序过程中是否更改/修改了集合。如果您希望在每次请求.first()和.last()时更确定检索相同的项,则应该实现一些更多的逻辑,如排序。

相关内容

最新更新