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

时间:2011-07-13 07:36:28

标签: .net linq ienumerable

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

因此,在重新审视了我对IEnumerable的假设之后,我得出的结论是,事实上你唯一可以肯定的是它允许你遍历集合的所有元素,其中集合(不是ICollection per se)可以是任何东西。

我认为我无法做出的另一个假设是底层集合的顺序是特定的。从理论上讲,每次循环时,你都可以按照不同的顺序获取物品。

现在回到原来的问题,考虑到上述问题,First()Last()每次都会返回不同的项目(从理论上看IEnumerable是什么)?

Exra信息: 当然,这通常会很好,因为IEnumerable是通过订购的东西实现的。但是,如果IEnumerable调用Web服务来获取其元素,该怎么办呢?

背景信息 我正在考虑这个因为我想为foreach循环中的第一个和最后一个元素做一些特定的事情。所以我检查了if(currentElement == Enumerable.Last())

6 个答案:

答案 0 :(得分:6)

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

Jon Skeet关于LINQ运算符的一系列非常有用的文章 - 请参阅Edulinq。他描述了每一个LINQ运算符,并详细讨论了所有的想法和假设。它可以非常好地了解所有这些事情是如何运作的。

答案 1 :(得分:3)

  

所以我检查了if(currentElement == Enumerable.Last())

Last()实际上是最后一个,但是它会枚举你的Enumerable。它不是免费或副作用。

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

答案 2 :(得分:1)

我认为在多线程环境中,.First.Last可能被证明是不确定的,特别是如果你不小心你的并发性。

答案 3 :(得分:0)

正如其他人提到的,如果您不知道底层枚举是什么,您可能不应该假设First()或Last()的行为与您期望的一样。但是,如果您已经要遍历IEnumerable并希望得到可枚举的当前状态的“快照”,那么您将能够保证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

}

答案 4 :(得分:0)

您可以使用Enumerable.OrderBy Method确保按照所需条件对可枚举进行排序,并获取您真正想要的第一个或最后一个项目。

答案 5 :(得分:-2)

Enumerable.first()和Enumerable.last()实际上是真正的第一个和最后一个元素。 在这种情况下,您必须指定您认为应该是第一个和最后一个元素。它强烈依赖于例如如何在Enumerable中对元素进行排序以及在处理过程中是否更改/修改集合。如果你想在每次请求.first()和.last()时更加确定检索相同的项目,你应该实现更多逻辑,比如排序。