getenumerator - return foreach c#




foreach vs someList.ForEach(){} (9)

Conozco dos cosas oscuras que los hacen diferentes. Veme!

En primer lugar, está el error clásico de crear un delegado para cada elemento de la lista. Si usa la palabra clave foreach, todos sus delegados pueden terminar refiriéndose al último elemento de la lista:

    // A list of actions to execute later
    List<Action> actions = new List<Action>();

    // Numbers 0 to 9
    List<int> numbers = Enumerable.Range(0, 10).ToList();

    // Store an action that prints each number (WRONG!)
    foreach (int number in numbers)
        actions.Add(() => Console.WriteLine(number));

    // Run the actions, we actually print 10 copies of "9"
    foreach (Action action in actions)
        action();

    // So try again
    actions.Clear();

    // Store an action that prints each number (RIGHT!)
    numbers.ForEach(number =>
        actions.Add(() => Console.WriteLine(number)));

    // Run the actions
    foreach (Action action in actions)
        action();

El método List.ForEach no tiene este problema. El elemento actual de la iteración se pasa por valor como un argumento al lambda externo, y luego el lambda interno captura correctamente ese argumento en su propio cierre. Problema resuelto.

(Lamentablemente, creo que ForEach es miembro de List, en lugar de un método de extensión, aunque es fácil definirlo usted mismo, por lo que tiene esta función en cualquier tipo enumerable).

En segundo lugar, el enfoque del método ForEach tiene una limitación. Si está implementando IEnumerable mediante el retorno de rendimiento, no puede hacer un retorno de rendimiento dentro de la lambda. Por lo tanto, este método no permite pasar por los elementos de una colección para poder devolver cosas. Deberá usar la palabra clave foreach y solucionar el problema de cierre haciendo manualmente una copia del valor del ciclo actual dentro del ciclo.

Más aquí

Aparentemente hay muchas maneras de iterar sobre una colección. Curioso si hay alguna diferencia, o por qué usaría una forma sobre la otra.

Primer tipo:

List<string> someList = <some way to init>
foreach(string s in someList) {
   <process the string>
}

Otra manera:

List<string> someList = <some way to init>
someList.ForEach(delegate(string s) {
    <process the string>
});

Supongo que, en lo alto de mi cabeza, en vez del delegado anónimo que uso arriba, tendrías un delegado reutilizable que podrías especificar ...


Considere el siguiente article sobre el rendimiento list.foreach.


El alcance completo de ForEach (función de delegado) se trata como una sola línea de código (que llama a la función), y no puede establecer puntos de interrupción o ingresar al código. Si ocurre una excepción no controlada, se marca todo el bloque.


Hay una distinción importante y útil entre los dos.

Debido a que .ForEach usa un ciclo for para iterar la colección, esto es válido (edit: antes de .net 4.5 - la implementación cambió y ambos lanzan):

someList.ForEach(x => { if(x.RemoveMe) someList.Remove(x); }); 

mientras que foreach usa un enumerador, entonces esto no es válido:

foreach(var item in someList)
  if(item.RemoveMe) someList.Remove(item);

tl; dr: ¡NO copie este código en su aplicación!

Estos ejemplos no son una buena práctica, solo son para demostrar las diferencias entre ForEach() y foreach .

Eliminar elementos de una lista dentro de un ciclo for puede tener efectos secundarios. El más común se describe en los comentarios a esta pregunta.

En general, si está buscando eliminar varios elementos de una lista, le conviene separar la determinación de qué elementos eliminar de la eliminación real. No mantiene compacto su código, pero garantiza que no se pierda ningún elemento.


La segunda manera que mostró utiliza un método de extensión para ejecutar el método de delegado para cada uno de los elementos en la lista.

De esta manera, tiene otra llamada de delegado (= método).

Además, existe la posibilidad de iterar la lista con un ciclo for .


List.ForEach () se considera más funcional.

List.ForEach() dice lo que quieres que se haga. foreach(item in list) también dice exactamente cómo lo quiere hacer. Esto deja a List.ForEach libre de cambiar la implementación del cómo en el futuro. Por ejemplo, una versión futura hipotética de .Net siempre podría ejecutar List.ForEach en paralelo, bajo la suposición de que en este punto todos tienen una cantidad de núcleos de CPU que generalmente están inactivos.

Por otro lado, foreach (item in list) le da un poco más de control sobre el bucle. Por ejemplo, usted sabe que los elementos se iterarán en algún tipo de orden secuencial, y podría romperse fácilmente en el medio si un elemento cumple alguna condición.


Puedes nombrar al delegado anónimo :-)

Y puedes escribir el segundo como:

someList.ForEach(s => s.ToUpper())

Lo cual prefiero, y ahorra un montón de tipeo.

Como dice Joachim, el paralelismo es más fácil de aplicar a la segunda forma.


Supongo que la llamada someList.ForEach() podría ser fácilmente paralelizada, mientras que el foreach normal no es tan fácil de ejecutar en paralelo. Podría ejecutar fácilmente varios delegados diferentes en núcleos diferentes, lo cual no es tan fácil de hacer con un foreach normal.
Solo mis 2 centavos


Una cosa de qué preocuparse es cómo salir del método Generic .ForEach: vea esta discusión . Aunque el enlace parece decir que de esta manera es el más rápido. No estoy seguro de por qué, uno pensaría que serían equivalentes una vez compilados ...







enumeration