开发者

Are First() and Last() on IEnumerable<> really the first and last?

I recently came to realize that you sho开发者_开发技巧uldn't make any assumptions on the implementation of an IEnumerable (for example that you can't assume that when you make changes to one of the objects that came from the IEnumerable during a foreach loop, that after the loop (or even after each iteration) the changed object can be found in the IEnumerable.

So after re-examining my assumptions about IEnumerable, I came to the conclusion that in fact the only thing you can know for sure is that it allows you to traverse all the elements of a collection, where a collection (not ICollection per se) can be anything.

Another assumption that I think that I cannot make is that the order of the underlying collection is something specific. Theoretically you could get the items in a different order everytime you loop over them I'd say.

Now to return to my original question, taking the above into account, First() and Last() could return different items every time (theoretically looking at what an IEnumerable is)?

Exra info: Of course usually this will be fine because the IEnumerable is implemented by something that is ordered. But what if the IEnumerable makes calls to a webservice to get its elements.

Background info: I was thinking about this because I wanted to do something specific for the first and last element in a foreach loop. So I checked if(currentElement == Enumerable.Last())


First() gets an enumerator and return first value that it founds. Last() most often iterates through the whole collection and returns element one before reaching the end of enumeration. And right, that's all you know for sure. Specifically, collection can be infinite and then Last() will never return.

There is very helpful series of articles about LINQ operators by Jon Skeet - see Edulinq. He describes every single LINQ operator and discuss all the ideas and assumptions in details. It gives very good insight in how all those things really work.


So I checked if(currentElement == Enumerable.Last())

Last() is really the last, but calling it enumerates your Enumerable. It is not free of cost or side-effects.

And that also gives you the definition of Last() : the last element that an iteration currently yields. Change the list and you may have another Last().


I'd imagine that in a multithreaded environment, .First and .Last could prove to be non-deterministic, especially if you're not careful with your concurrency.


As others mentioned, if you don't know what the underlying enumerable is, you probably shouldn't assume that First() or Last() behave as you would expect. However if you're already going to be looping over the IEnumerable and want to get a 'snapshot' of the current state of the enumerable, then you'd be able to guarantee First() and Last() behave as expected. I would convert the IEnumerable to a list (or array) like this and then you shouldn't have any problems:

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

}


You can use Enumerable.OrderBy Method to make sure that the enumerable is ordered by the desirable criteria and to get the first or last items you realy want.


The Enumerable.first() and Enumerable.last() are in fact the real first and last elements. In this case you have to specify what you think should be the first and last element. It strongly depends on for example how you sort your elements inside the Enumerable and if the collection is changed / modified during the proces. If you want to be more sure on retrieving the same items everytime you request .first() and .last() you should implement some more logic like sorting.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜