It isn't available because IEnumerator
is a forward only iterator. It only has a MoveNext()
method. That makes the interface very universal and the core of Linq. There are lots of real world collections that cannot be iterated backwards because that requires storage. Most streams are like that for example.
Linq provides a solution with the Reverse()
extension method. It works by storing the elements first, then iterating them backwards. That however can be very wasteful, it requires O(n) storage. It is missing a possible optimization for collections that are already indexable. Which you can fix:
static class Extensions {
public static IEnumerable<T> ReverseEx<T>(this IEnumerable<T> coll) {
var quick = coll as IList<T>;
if (quick == null) {
foreach (T item in coll.Reverse()) yield return item;
}
else {
for (int ix = quick.Count - 1; ix >= 0; --ix) {
yield return quick[ix];
}
}
}
}
Sample usage:
var list = new List<int> { 0, 1, 2, 3 };
foreach (var item in list.ReverseEx()) {
Console.WriteLine(item);
}
You'll want to make a specialization for LinkedList since it doesn't implement IList<T>
but still allows quick backwards iteration through the Last
and LinkedListNode.Previous
properties. Although it is much better to not use that class, it has lousy CPU cache locality. Always favor List<T>
when you don't need cheap inserts. It could look like this:
public static IEnumerable<T> ReverseEx<T>(this LinkedList<T> list) {
var node = list.Last;
while (node != null) {
yield return node.Value;
node = node.Previous;
}
}
MoveNext()
would kinda seem an oxymoron for a reverse enumerator though I guess for compatibility withforeach
theGetReverseEnumerator()
method would actually still have to return aIEnumerator
and thus would require that method even ifMovePrevious()
would seem more appropriate to my mind – CorrelateIList<T>
we get an efficientReverse
from linq. Unfortunately not every type that can implementReverse
efficiently, can also implementIList<T>
. For example a doubly linked list. So I agree, that those collections having a built inReverse()
method, would be nice. – Affiantforeachreverse
construct instead – PmEnumerable.Reverse()
creates a copy of the whole sequence, even forIList<T>
. See Jon Skeet's blog. – Shanna