c# - framework - La colección fue modificada; la operación de enumeración no se puede ejecutar en ArrayList
colección modificada la operación de enumeración no se puede ejecutar (9)
¿Me estoy perdiendo de algo? Alguien me corrige si estoy equivocado.
list.RemoveAll(s => s.Name == "Fred");
Esta pregunta ya tiene una respuesta aquí:
Estoy tratando de eliminar un elemento de una ArrayList
y recibo esta excepción:
Collection was modified; enumeration operation may not execute.
¿Algunas ideas?
Aquí hay un ejemplo (lo siento por cualquier error tipográfico)
var itemsToRemove = new ArrayList(); // should use generic List if you can
foreach (var item in originalArrayList) {
if (...) {
itemsToRemove.Add(item);
}
}
foreach (var item in itemsToRemove) {
originalArrayList.Remove(item);
}
O si está utilizando 3.5, Linq hace que el primer bit sea más fácil:
itemsToRemove = originalArrayList
.Where(item => ...)
.ToArray();
foreach (var item in itemsToRemove) {
originalArrayList.Remove(item);
}
Reemplace "..." con su condición que determina si el artículo debe ser eliminado.
En lugar de foreach (), use un bucle for () con un índice numérico.
Estás eliminando el artículo durante un foreach
, ¿sí? Simplemente, no puedes. Hay algunas opciones comunes aquí:
- use
List<T>
yRemoveAll
con un predicado iterar hacia atrás por índice, eliminando elementos coincidentes
for(int i = list.Count - 1; i >= 0; i--) { if({some test}) list.RemoveAt(i); }
utilice
foreach
y coloque los elementos coincidentes en una segunda lista; ahora enumere la segunda lista y elimine esos elementos de la primera (si ve lo que quiero decir)
Estoy de acuerdo con varios de los puntos que he leído en esta publicación y los he incorporado a mi solución para resolver exactamente el mismo problema que la publicación original.
Dicho esto, los comentarios que aprecio son:
"a menos que use .NET 1.0 o 1.1, use
List<T>
lugar deArrayList
"."Además, agregue los elementos que desea eliminar a una nueva lista. Luego, vaya y elimine esos elementos". .. en mi caso, acabo de crear una nueva lista y la llené con los valores de datos válidos.
p.ej
private List<string> managedLocationIDList = new List<string>();
string managedLocationIDs = ";1321;1235;;" // user input, should be semicolon seperated list of values
managedLocationIDList.AddRange(managedLocationIDs.Split(new char[] { '';'' }));
List<string> checkLocationIDs = new List<string>();
// Remove any duplicate ID''s and cleanup the string holding the list if ID''s
Functions helper = new Functions();
checkLocationIDs = helper.ParseList(managedLocationIDList);
...
public List<string> ParseList(List<string> checkList)
{
List<string> verifiedList = new List<string>();
foreach (string listItem in checkList)
if (!verifiedList.Contains(listItem.Trim()) && listItem != string.Empty)
verifiedList.Add(listItem.Trim());
verifiedList.Sort();
return verifiedList;
}
Me gusta iterar hacia atrás usando un bucle for
, pero esto puede ser tedioso en comparación con foreach
. Una solución que me gusta es crear un enumerador que atraviese la lista hacia atrás. Puede implementar esto como un método de extensión en ArrayList
o List<T>
. La implementación de ArrayList
está a continuación.
public static IEnumerable GetRemoveSafeEnumerator(this ArrayList list)
{
for (int i = list.Count - 1; i >= 0; i--)
{
// Reset the value of i if it is invalid.
// This occurs when more than one item
// is removed from the list during the enumeration.
if (i >= list.Count)
{
if (list.Count == 0)
yield break;
i = list.Count - 1;
}
yield return list[i];
}
}
La implementación de List<T>
es similar.
public static IEnumerable<T> GetRemoveSafeEnumerator<T>(this List<T> list)
{
for (int i = list.Count - 1; i >= 0; i--)
{
// Reset the value of i if it is invalid.
// This occurs when more than one item
// is removed from the list during the enumeration.
if (i >= list.Count)
{
if (list.Count == 0)
yield break;
i = list.Count - 1;
}
yield return list[i];
}
}
El ejemplo siguiente utiliza el enumerador para eliminar todos los enteros pares de una ArrayList
.
ArrayList list = new ArrayList() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
foreach (int item in list.GetRemoveSafeEnumerator())
{
if (item % 2 == 0)
list.Remove(item);
}
No modifique la lista dentro de un bucle que itera por la lista.
En su lugar, use a for()
o while()
con un índice, yendo hacia atrás en la lista. (Esto le permitirá eliminar cosas sin obtener un índice inválido).
var foo = new List<Bar>();
for(int i = foo.Count-1; i >= 0; --i)
{
var item = foo[i];
// do something with item
}
Una forma es agregar los elementos que se eliminarán a una nueva lista. Luego revise y elimine esos elementos.
usando ArrayList
también puedes probar así
ArrayList arraylist = ... // myobject data list
ArrayList temp = (ArrayList)arraylist.Clone();
foreach (var item in temp)
{
if (...)
arraylist.Remove(item);
}