Un po 'di una risposta lunga, le due risposte precedenti coprono la maggior parte di essa, ma ho trovato alcuni aspetti che ho trovato interessante quando guardando foreach nella specifica C#
lingua. A meno che tu non sia interessato a questo, smetti di leggere.
Ora verso la parte intering, secondo C#
espansione specifiche delle seguenti affermazioni:
foreach (V v in x) embedded-statement
gves voi:
{`
E e = ((C)(x)).GetEnumerator();
try {
while (e.MoveNext()) {
V v = (V)(T)e.Current;
embedded-statement
}
}
finally {
… // Dispose e
}
}
Avere un qualche tipo di funzione identità che segue x == ((C)(x)).GetEnumerator()
(è è il proprio enumeratore) e l'uso dei loop di @ JonSkeet produce qualcosa del genere (rimosso try/catch per brevità):
var list = new List<int> { 1, 2, 3 };
while (list.MoveNext()) {
int x = list.Current; // x is always 1
while (list.MoveNext()) {
int y = list.Current; // y becomes 2, then 3
Console.WriteLine("{0} {1}", x, y);
}
}
stamperà qualcosa sulla falsariga di:
1 2
1 3
E poi list.MoveNext()
tornerà false
sempre. Il che rende un punto molto importante, se si guarda a questo:
var list = new List<int> { 1, 2, 3 };
// loop
foreach (var x in list) Console.WriteLine(x); // Will print 1,2,3
// loop again
// Will never enter loop, since reset wasn't called and MoveNext() returns false
foreach (var y in list) Console.WriteLine(x); // Print nothing
Quindi, con il suddetto in mente, e notare che è assolutamente fattibile in quanto la dichiarazione foreach
cerca un GetEnumerator()
-Metodo prima di controllare se o no il tipo implementa IEnumerable<T>
:
Perché è stato l'approccio di cui sopra non ha seguito ed i problemi che si troveranno ad affrontare se lo seguo?
Non puoi nido loop, né è possibile utilizzare l'istruzione foreach
di accedere alla stessa collezione più di una volta senza chiamare Reset()
manualmente tra di loro. Inoltre cosa succede quando smaltiamo l'enumeratore dopo ogni foreach
?
In che modo la presenza dell'interfaccia IEnumerator risolve questi problemi?
Tutte le iterazioni sono indipendenti l'una dall'altra, sia che si tratti di nidificazione, più thread ecc., L'enumerazione è separata dalla raccolta stessa. Lo si può considerare un po 'come separations of concerns, or SoC, poiché l'idea è quella di separare l'attraversamento dalla lista stessa e che l'attraversamento in nessun caso dovrebbe alterare lo stato della raccolta. IE una chiamata a MoveNext()
con il tuo esempio potrebbe modificare la raccolta.
pensiero rapido; è usato principalmente per il ciclo foreach - roba del compilatore !! – codebased
GetEnumerator restituisce un nuovo enumeratore in modo che più enumeratori possano navigare indipendentemente attraverso una raccolta. Con la tua soluzione non è possibile. – Jehof
@flindeberg Non c'è tag tag. Non sta facendo nulla in modo improprio. – Servy