2010-06-09 11 views
6

Possible Duplicates:
Exception during iteration on collection and remove items from that collection
How to remove elements from a generic list while iterating around it?
Better way to remove matched items from a listlo bien eliminar elemento de la lista

// tmpClientList is List<Client> type 

if (txtboxClientName.Text != "") 
    foreach (Client cli in tmpClientList) 
     if (cli.Name != txtboxClientName.Text) 
      tmpClientList.Remove(cli); 

de error: "Colección se modificó, la operación de enumeración no puede ejecutar."

¿Cómo puedo eliminar elementos de la lista, de una manera simple, sin guardar los índices de estos elementos en otra lista o matriz, y eliminarlos en otro lugar en el código. Probé también RemoveAt (índice) pero es exactamente la misma situación, modificando cuando se ejecuta el bucle.

+0

Acordado en problemas duplicados exactos, vea el enlace Uno http://stackoverflow.com/questions/1154325/better-way-to-remove-matched-items-from-a-list y enlace dos: http: //stackoverflow.com/questions/1541777/can-you-remove-an-item-from-a-list-whilst-iterating-through-it-in-c – CrimsonX

Respuesta

1

El problema es que está intentando modificar la lista en una iteración de foreach. Reemplace eso con un for y debería estar bien.

Además, como parece que está utilizando la entrada del usuario para el nombre, considere limpiar la entrada un poco, al menos con un Trim() para eliminar espacios en blanco adicionales. Si no lo haces, 'John' y 'John' serán dos cosas diferentes. Lo mismo para la verificación inicial! = "".

+0

quieres decir que "" y "" serían los lo mismo, y debo recortar la entrada en esa situación también (cuando el usuario escribe solo caracteres blancos como entrada)? – qlf00n

+0

@dygi: sí. la eliminación de espacios en blanco deja solo la información relevante, que en este caso es ninguna. En cuanto a un caso en el que esto podría suceder: el usuario comienza a escribir el nombre, incluido un espacio después de él, luego decide eliminar los caracteres y el espacio queda, ya que no puede "verlo". – Rox

2

No utilizar foreach. Use para y desciende la lista (es decir, comience desde el final), usando RemoveAt.

Así,

// tmpClientList is List<Client> type 

if (txtboxClientName.Text != "") 
    foreach (int pos = tmpClientList.Length - 1; pos >= 0; pos--) 
    { 
     Client cli = tmpClientList[pos]; 
     if (cli.Name != txtboxClientName.Text) 
      tmpClientList.RemoveAt(pos); 
    } 
4

O bien utilizar un for/while, o tmpClientList.RemoveAll(a => a.Name == txtboxClientName.Text). Como no especificaste la versión de C# que estás usando, ymmw.

+1

Y cuando se limita a 2.0, es un poco más detallado: 'tmpClientList.RemoveAll (delegado (Cliente a) {return a.Name == txtboxClientName.Text;});' – Humberto

11

Retrocedamos por la lista ... de esta forma, eliminar un elemento no afecta al siguiente.

for(var i=tmpClientList.Count-1;i>=0;i--) 
{ 
    if (tmpClientList[i].Name != txtboxClientName.Text) 
      tmpClientList.RemoveAt(i); 

} 
+0

buena solución simple, gracias por compartir – qlf00n

11

En un List<T>, hay un método RemoveAll que se lleva a un delegado para indicar si desea eliminar el elemento. Se puede utilizar de esta manera:

tmpCLientList.RemoveAll(cli => cli.Name != txtboxClientName.Text); 
+0

+1 Se debe tener en cuenta que esto solo funciona para C# 3.0 y posteriores. El OP marcó la pregunta con las versiones 2, 3 y 4 :-) –

+1

@Jakob: Si el OP no usa C# 3 o posterior, entonces pueden llamar a 'RemoveAll' con la sintaxis del delegado old-skool:' tmpCLientList.RemoveAll (delegar (Cli del cliente) {return cli.Name! = txtboxClientName.Text;}); ' – LukeH

+0

Oh, claro, pensó que RemoveAll era un método de extensión. Perdón por eso :-) –

1

puede crear otra lista con los elementos que desee eliminar y repetir la nueva lista para eliminar elementos de la lista "txtboxClientName".

+0

Correcto, puedo usar los métodos Contiene() y Eliminar() en la lista de copias, mientras realizo la iteración sobre la original. Gracias. – qlf00n

1

En realidad, foreach utiliza Enumerators para iterar a través de determinadas colecciones de elementos. Yendo más lejos, el System.Collections.Generic.List<T> implementa el IEnumarable-Interface al provide a Class, que sabe cómo recorrer los elementos de la lista, es decir, el Enumerator. Ahora bien, si itera a través de esa lista mediante el uso de foreach, el Enumerador realiza un seguimiento de la posición actual, cómo llegar a la siguiente posición y algunas otras cosas. La lógica interna podría ser algo así como almacenar el número de elementos en una variable ny luego acceder a todos los objetos desde 0 hasta n-1. Como puede observar, si se elimina algún objeto entre los pasos de iteración, finalizaremos en un NullReferenceException cuando el enumerador intente entregar el último objeto de la lista. Por lo tanto, para evitar fallas de iteración, no se permite modificar la lista en sí durante la enumeración.

Espero poder decirlo al menos un poco de manera exhaustiva. :-)

+0

gracias por la información muy precisa, GTK cómo funciona internamente – qlf00n

Cuestiones relacionadas