views:

167

answers:

4

Logically, one would think that the foreach loop in C# would evaluate in the same order as an incrementing for loop. Experimentally, it does. However, there appears to be no such confirmation on the MSDN site.

Is it simply such an apparent answer that they did not think to include that information on the site? Or is there the possibility that it will behave erratically?

+11  A: 

For arrays (note that System.Array implements IEnumerable), it will access elements in order. For other types (IEnumerable, or having GetEnumerator), it accesses elements in the order provided, through alternating MoveNext and Current calls.

The standard states (ECMA-364 §15.8.4):

"The order in which foreach traverses the elements of an array, is as follows: For single-dimensional arrays elements are traversed in increasing index order, starting with index 0 and ending with index Length – 1. For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are increased first, then the next left dimension, and so on to the left."

Matthew Flaschen
+3  A: 

For what it's worth, you can look up a lot of this in Reflector. In mscorlib, System.Array implements IEnumerable (as mentioned), and Array#GetEnumerator returns an ArrayEnumerator. Here's the body of ArrayEnumerator#MoveNext:

public bool MoveNext()
{
    if (this._complete)
    {
        this.index = this.endIndex;
        return false;
    }
    this.index++;
    this.IncArray();
    return !this._complete;
}

That's obviously one example, but the answer is: it's up to the implementer and you can find out most of the way they work experimentally, or by inspecting the source, in some cases.

Marc Bollinger
+4  A: 

foreach is built on top of IEnumerable<T> The contract for the enumerator on MSDN says

Initially, the enumerator is positioned before the first element in the collection. ... Therefore, you must call MoveNext to advance the enumerator to the first element of the collection before reading the value of Current.

Current returns the same object until MoveNext is called. MoveNext sets Current to the next element.

So if the underlying collection has clear 'first' element, and each element has a clear 'next' element, as is the case for arrays, lists and so on, then you can expect that the foreach to behave logically and stably. If it is something like a set, which has no first or next sequence, then it may behave in an unstable manner, though presumably without changing the IEnumerable's state even collections which have no defined order will be consistent, as making them inconsistent would be more work!

Pete Kirkham
+2  A: 

The caveat on foreach are Hash Arrays where order is not guaranteed due to ... hash keys.

ddm