views:

770

answers:

6

Is there a way to use yield blocks to implement an IEnumerator<T> which can go backward (MoveLast()) as well as forward?

+4  A: 

No, the state machine generated by the C# compiler is strictly forward.

It doesn't even make sense to go backwards in many cases. Imagine an iterator reading from a network stream - to go backwards, it would have to remember everything that it had ever read, because it couldn't rewind time and ask the network for the data again.

(Ditto anything that generated data in some lossy way. Imagine an iterator which returned a new board for Conway's Life on each iteration - there are multiple boards which could all have been the previous one, so to go backwards you again have to remember what you've already returned.)

Jon Skeet
Obviously in many cases it doesn't make sense, yes. It's just a pity that we don't get any help when it does.
Alexey Romanov
Well we don't have any language support for *iterating* backwards either. I have to say, I can't remember the last time I needed to do it. Do you find yourself regularly in such a situation?
Jon Skeet
A: 

No. Using yield results in an IEnumerable which is unidirectional.

David Schmitt
For completeness: or an IEnumerator[<T>]
Marc Gravell
+2  A: 

Not directly from the iterator block, no.

However, the caller can always buffer the results, for example into a List<T>, or just call Reverse() - but this doesn't always apply.

Marc Gravell
Yes, that's the obvious solution. I was hoping there was an alternative I was missing.
Alexey Romanov
@alexey_r - not much else you can do, though - for all the reasons that Jon gives.
Marc Gravell
A: 

C5 Collections library (http://www.itu.dk/research/c5/) implements collections and linked list with backwards enumeration. The project is OpenSource so you should be able to find answer there.

Timur Fanshteyn
+1  A: 

No. One of the limitations of IEnumerator is that it holds its current state, and it doesn't remember its prior state. As a result, IEnumerable is forward-only.

If you need to hold onto prior states, read the IEnumerable into a List or LinkedList and enumerate through those objects instead.

Juliet
A: 

Actually, there seems to be an approach described in Accelerated C# 2008. Unfortunately, two pages are not visible in the preview, and it has to rely on reflection (the results of which can be cached, as usual) but you can get the gist.

Alexey Romanov
That makes a bidirectional iterator from a LinkedList. That is easy enough. The difficulty lies in implementing one from just an IEnumerable.
Rasmus Faber