¿Cuál es la mejor manera de modificar una lista en un bucle 'foreach'?

Resuelto Polo asked hace 15 años • 11 respuestas

Una nueva característica en C#/.NET 4.0 es que puede cambiar su enumerable en a foreachsin obtener la excepción. Consulte la entrada del blog de Paul Jackson Un efecto secundario interesante de la concurrencia: eliminar elementos de una colección mientras se enumeran para obtener información sobre este cambio.

¿Cuál es la mejor manera de hacer lo siguiente?

foreach(var item in Enumerable)
{
    foreach(var item2 in item.Enumerable)
    {
        item.Add(new item2)
    }
}

Por lo general, uso un IListcaché/búfer hasta el final del mismo foreach, pero ¿hay una mejor manera?

Polo avatar Apr 17 '09 17:04 Polo
Aceptado

La colección utilizada en foreach es inmutable. Esto es en gran medida por diseño.

Como dice en MSDN :

La declaración foreach se usa para recorrer la colección y obtener la información que desea, pero no se puede usar para agregar o eliminar elementos de la colección fuente para evitar efectos secundarios impredecibles. Si necesita agregar o eliminar elementos de la colección fuente, use un bucle for.

La publicación en el enlace proporcionado por Poko indica que esto está permitido en las nuevas colecciones simultáneas.

Rik avatar Apr 17 '2009 10:04 Rik

Haga una copia de la enumeración, utilizando en este caso un método de extensión IEnumerable, y enumere sobre ella. Esto agregaría una copia de cada elemento en cada enumerable interno a esa enumeración.

foreach(var item in Enumerable)
{
    foreach(var item2 in item.Enumerable.ToList())
    {
        item.Add(item2)
    }
}
tvanfosson avatar Apr 17 '2009 10:04 tvanfosson

Para ilustrar la respuesta de Nippysaurus: si va a agregar los nuevos elementos a la lista y desea procesar los elementos recién agregados también durante la misma enumeración, puede usar el bucle for en lugar del bucle foreach , problema resuelto :)

var list = new List<YourData>();
... populate the list ...

//foreach (var entryToProcess in list)
for (int i = 0; i < list.Count; i++)
{
    var entryToProcess = list[i];

    var resultOfProcessing = DoStuffToEntry(entryToProcess);

    if (... condition ...)
        list.Add(new YourData(...));
}

Por ejemplo ejecutable:

void Main()
{
    var list = new List<int>();
    for (int i = 0; i < 10; i++)
        list.Add(i);

    //foreach (var entry in list)
    for (int i = 0; i < list.Count; i++)
    {
        var entry = list[i];
        if (entry % 2 == 0)
            list.Add(entry + 1);

        Console.Write(entry + ", ");
    }

    Console.Write(list);
}

Salida del último ejemplo:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5, 7, 9,

Lista (15 elementos)
0
1
2
3
4
5
6
7
8
9
1
3
5
7
9

Roland Pihlakas avatar Aug 26 '2015 12:08 Roland Pihlakas