2010-06-22 23 views
21

Logicamente, si potrebbe pensare che il ciclo foreach in C# valuti nello stesso ordine di un ciclo di incremento per ciclo. Sperimentalmente, lo fa. Tuttavia, sembra che non ci sia alcuna conferma sul sito MSDN.Il ciclo foreach in C# garantisce un ordine di valutazione?

È semplicemente una risposta così evidente che non hanno pensato di includere tali informazioni sul sito? O c'è la possibilità che si comporti in modo irregolare?

risposta

35

Per gli array (notare che System.Array implementa IEnumerable), accederà agli elementi nell'ordine. Per altri tipi (IEnumerable o GetEnumerator), accede agli elementi nell'ordine fornito, alternando le chiamate MoveNext e Current.

Lo standard (ECMA-364 §15.8.4):

"L'ordine in cui foreach attraversa gli elementi di una matrice, è segue: Per gli array monodimensionale elementi sono attraversato ascendente ordine di indice, partendo con indice 0 e termina con indice Lunghezza - 1. Per array multidimensionali, elementi attraversati tale che gli indici della dimensione destra sono aumentati , poi la dimensione prossima a sinistra , e così via a sinistra. "

5

Per quello che vale, è possibile cercare un sacco di questo in Reflector. In mscorlib, System.Array implementa IEnumerable (come indicato) e Array#GetEnumerator restituisce un ArrayEnumerator. Ecco il corpo di ArrayEnumerator#MoveNext:

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

Questo è ovviamente un esempio, ma la risposta è: tocca al realizzatore e si possono trovare la maggior parte del loro modo di lavorare sperimentalmente, o controllando la fonte, in alcuni casi .

11

foreach è costruito in cima IEnumerable<T> Il contratto per l'enumeratore sulla MSDN dice

Inizialmente, l'enumeratore è posizionato prima del primo elemento della collezione. ... Pertanto, è necessario chiamare MoveNext per far avanzare l'enumeratore sul primo elemento della raccolta prima di leggere il valore di Current.

Current restituisce lo stesso oggetto fino a quando viene chiamato MoveNext. MoveNext imposta Current sull'elemento successivo.

Quindi, se la raccolta sottostante ha chiaro elemento 'prima', e ogni elemento ha un elemento chiaro 'prossimo', come è il caso per gli array, liste e così via, allora ci si può aspettare che il foreach comportarsi logicamente e stabilmente. Se è qualcosa come un set, che non ha una sequenza prima o successiva, allora può comportarsi in modo instabile, sebbene presumibilmente senza modificare lo stato di IEnumerable anche le collezioni che non hanno un ordine definito saranno coerenti, poiché renderle incoerenti sarebbe più lavoro!

3

L'avvertenza su foreach è Hash Array in cui l'ordine non è garantito a causa di ... chiavi hash.

Problemi correlati