¿Cuál es la mejor manera de modificar una lista en un bucle 'foreach'?
Una nueva característica en C#/.NET 4.0 es que puede cambiar su enumerable en a foreach
sin 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 IList
caché/búfer hasta el final del mismo foreach
, pero ¿hay una mejor manera?
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.
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)
}
}
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