while sintaxis hacer for explicacion ejemplo como ciclo bucles bucle c# iterator ienumerable loops

sintaxis - ¿Cuándo debería usar IEnumerator para el bucle en c#?



foreach c# explicacion (4)

De acuerdo con la especificación del lenguaje C # :

Una declaración foreach del formulario

foreach (V v in x) embedded-statement

luego se expande a:

{ E e = ((C)(x)).GetEnumerator(); try { V v; while (e.MoveNext()) { v = (V)(T)e.Current; embedded-statement } } finally { ... // Dispose e } }

La esencia de tus dos ejemplos es la misma, pero hay algunas diferencias importantes, sobre todo el try / finally .

Me preguntaba si hay ocasiones en las que sea ventajoso usar un IEnumerator en un bucle foreach para iterar a través de una colección. Por ejemplo, ¿hay algún momento en el que sea mejor usar cualquiera de los siguientes ejemplos de código sobre el otro?

IEnumerator<MyClass> classesEnum = myClasses.GetEnumerator(); while(classesEnum.MoveNext()) Console.WriteLine(classesEnum.Current);

en lugar de

foreach (var class in myClasses) Console.WriteLine(class);


En C #, foreach está haciendo exactamente lo mismo que el código de IEnumerator que publicó anteriormente. La construcción foreach se proporciona para que sea más fácil para el programador. Creo que el IL generado en ambos casos es el mismo / similar.


Lo usé a veces cuando la primera iteración hace algo diferente de los demás.

Por ejemplo, si desea imprimir miembros a la consola y separar resultados por línea, puede escribir.

using (IEnumerator<MyClass> classesEnum = myClasses.GetEnumerator()) { if (classEnum.MoveNext()) Console.WriteLine(classesEnum.Current); while (classesEnum.MoveNext()) { Console.WriteLine("-----------------"); Console.WriteLine(classesEnum.Current); } }

Entonces el resultado es

myClass 1 ----------------- myClass 2 ----------------- myClass 3

Y otra situación es cuando itero 2 enumeradores juntos.

using (IEnumerator<MyClass> classesEnum = myClasses.GetEnumerator()) { using (IEnumerator<MyClass> classesEnum2 = myClasses2.GetEnumerator()) { while (classesEnum.MoveNext() && classEnum2.MoveNext()) Console.WriteLine("{0}, {1}", classesEnum.Current, classesEnum2.Current); } }

resultado

myClass 1, myClass A myClass 2, myClass B myClass 3, myClass C

Usar el enumerador le permite hacer más flexible en su iteración. Pero en la mayoría de los casos, puedes usar foreach


Primero, tenga en cuenta que una gran diferencia en su ejemplo (entre foreach y GetEnumerator ) es que foreach garantiza llamar a Dispose() en el iterador si el iterador es IDisposable . Esto es importante para muchos iteradores (que podrían estar consumiendo un feed de datos externo, por ejemplo).

De hecho, hay casos en los que foreach no es tan útil como nos gustaría.

Primero, está el caso del "primer ítem" discutido aquí (foreach / detección de la primera iteración) .

Pero más; Si intenta escribir el método Zip falta para unir dos secuencias enumerables (o el método SequenceEqual ), encontrará que puede usar foreach en ambas secuencias, ya que eso haría una combinación cruzada. Necesita usar el iterador directamente para uno de ellos:

static IEnumerable<T> Zip<T>(this IEnumerable<T> left, IEnumerable<T> right) { using (var iter = right.GetEnumerator()) { // consume everything in the first sequence foreach (var item in left) { yield return item; // and add an item from the second sequnce each time (if we can) if (iter.MoveNext()) { yield return iter.Current; } } // any remaining items in the second sequence while (iter.MoveNext()) { yield return iter.Current; } } } static bool SequenceEqual<T>(this IEnumerable<T> left, IEnumerable<T> right) { var comparer = EqualityComparer<T>.Default; using (var iter = right.GetEnumerator()) { foreach (var item in left) { if (!iter.MoveNext()) return false; // first is longer if (!comparer.Equals(item, iter.Current)) return false; // item different } if (iter.MoveNext()) return false; // second is longer } return true; // same length, all equal }