La colección fue modificada; la operación de enumeración no puede ejecutarse en ArrayList [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Estoy tratando de eliminar un elemento de un ArrayList y obtengo esta excepción:
Collection was modified; enumeration operation may not execute.

¿Alguna idea?

Author: Kay Lee, 2010-01-08

9 answers

Usted está quitando el elemento durante un foreach, sí? Simplemente, no se puede. Hay algunas opciones comunes aquí:

  • use List<T> y RemoveAll 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);
    }
    
  • Use foreach, y ponga 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)

 179
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-07 22:34:22

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á usando 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);
}

Reemplazar "..."con su condición que determina si el elemento debe ser eliminado.

 20
Author: Will,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-07 22:46:47

Una forma es agregar el elemento(s) que se eliminará (n) a una nueva lista. Luego ir a través y eliminar esos elementos.

 8
Author: ozczecho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-07 22:35:41

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 recorre la lista hacia atrás. Puede implementar esto como un método de extensión en ArrayList o List<T>. La implementación para ArrayList es la siguiente.

    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 para 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 siguiente ejemplo usa el enumerador para eliminar todos los enteros pares de un 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);
    }
 7
Author: Joe B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-26 15:16:40

No modifique la lista dentro de un bucle que itere a través de la lista.

En su lugar, use un for() o while() con un índice, yendo hacia atrás a través de la lista. (Esto le permitirá eliminar cosas sin obtener un índice no válido.)

var foo = new List<Bar>();

for(int i = foo.Count-1; i >= 0; --i)
{
  var item = foo[i];
  // do something with item
}
 5
Author: 3Dave,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-17 16:17:50

¿Me estoy perdiendo algo? Que alguien me corrija si me equivoco.

list.RemoveAll(s => s.Name == "Fred");
 4
Author: KevinDeus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-07 20:15:15

En lugar de foreach(), use un bucle for() con un índice numérico.

 2
Author: Seva Alekseyev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-07 22:35:21

Estoy de acuerdo con varios de los puntos que he leído en este post y los he incorporado en mi solución para resolver exactamente el mismo problema que la publicación original.

Dicho esto, los comentarios que aprecié son:

  • "a menos que esté usando. NET 1.0 o 1.1, use List<T> en lugar de ArrayList. "

  • "Además, agregue el (los) elemento (s) que se eliminará (n) a una nueva lista. Luego ir a través y eliminar esos elementos." .. en mi caso acabo de crear una nueva Lista y la rellené con el valores de datos válidos.

Por ejemplo

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;
}        
 2
Author: Brian Wells,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-29 15:34:39

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);
}
 1
Author: Nikson Kanti Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-24 07:19:59