2010-06-22 22 views
21

Lógicamente, uno pensaría que el bucle foreach en C# se evaluaría en el mismo orden que un bucle incremental. Experimentalmente, lo hace. Sin embargo, parece que no existe tal confirmación en el sitio de MSDN.¿El bucle foreach en C# garantiza un orden de evaluación?

¿Es simplemente una respuesta tan evidente que no pensaron incluir esa información en el sitio? ¿O existe la posibilidad de que se comporte de manera errática?

Respuesta

35

Para las matrices (tenga en cuenta que System.Array implementa IEnumerable), accederá a los elementos en orden. Para otros tipos (IEnumerable, o que tiene GetEnumerator), accede a los elementos en el orden proporcionado, alternando las llamadas MoveNext y Current.

Los estados estándar (ECMA-364 §15.8.4):

"El orden en que foreach atraviesa los elementos de una matriz, es como sigue: Para las matrices unidimensionales elementos están atravesado en el aumento de orden de índice, comenzando con el índice 0 y terminando con índice Longitud - 1. Para matrices multidimensionales, los elementos se atravesados ​​de tal manera que los índices de la dimensión más a la derecha se incrementan primero luego la siguiente dimensión, izquierda , y así sucesivamente a la izquierda ".

5

Por lo que vale, puede buscar mucho de esto en Reflector. En mscorlib, System.Array implementa IEnumerable (como se menciona) y Array#GetEnumerator devuelve ArrayEnumerator. Aquí está el cuerpo de ArrayEnumerator#MoveNext:

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

Eso es, evidentemente, un ejemplo, pero la respuesta es: depende de la implementador y se puede encontrar la mayor parte de su forma de trabajar de forma experimental, o mediante la inspección de la fuente, en algunos casos .

11

foreach se construye en la parte superior de IEnumerable<T> El contrato para el empadronador en MSDN dice

Inicialmente, el enumerador se coloca antes de que el primer elemento de la colección. ... Por lo tanto, debe llamar a MoveNext para avanzar al enumerador al primer elemento de la colección antes de leer el valor de Actual.

Current devuelve el mismo objeto hasta que se llame a MoveNext. MoveNext establece Current para el siguiente elemento.

lo tanto, si la colección subyacente tiene claro elemento 'primero', y cada elemento tiene un claro elemento 'siguiente', como es el caso de matrices, listas y así sucesivamente, entonces se puede esperar que el foreach se comporte Lógicamente y establemente Si es algo así como un conjunto, que no tiene una secuencia primera o siguiente, entonces puede comportarse de una manera inestable, aunque presumiblemente sin cambiar el estado de IEnumerable, incluso las colecciones que no tienen un orden definido serán consistentes, ya que hacerlas inconsistentes sería más ¡trabajo!

3

La advertencia en foreach son las matrices hash donde el orden no está garantizado debido a ... las teclas hash.