2010-06-09 19 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 listcome correttamente rimuovere elemento dalla lista

// tmpClientList is List<Client> type 

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

errore: "Collection è stata modificata; l'operazione di enumerazione non può eseguire"

Come posso rimuovere elementi dall'elenco, in un modo semplice, senza salvare gli indici di questi elementi in un altro elenco o array e rimuoverli in un altro punto del codice. Provato anche RemoveAt (index) ma è esattamente la stessa situazione, modificando quando viene eseguito il ciclo.

+0

Concordato su problemi duplicati esatti, vedere il collegamento One http://stackoverflow.com/questions/1154325/better-way-to-remove-matched-items-from-a-list e collegamento due: http: //stackoverflow.com/questions/1541777/can-you-remove-an-item-from-a-list-whilst-iterating-through-it-in-c – CrimsonX

risposta

1

Il problema è che si sta tentando di modificare l'elenco in una foreach iterazione. Sostituiscilo con un for e dovresti essere ok.

Inoltre, dal momento che sembra che si stia utilizzando l'input dell'utente per il nome, è consigliabile pulire un po 'l'input, almeno con un Trim() per rimuovere gli spazi bianchi extra. Se non lo fai, "John" e "John" saranno due cose diverse. Lo stesso per il controllo iniziale! = "".

+0

vuoi dire che "" e "" sarebbe il lo stesso, e dovrei tagliare l'input anche in quella situazione (quando l'utente digita solo caratteri bianchi come input)? – qlf00n

+0

@dygi: si. rimuovendo gli spazi bianchi lascia solo le informazioni rilevanti - che in questo caso non è nessuna. Come per un caso in cui ciò potrebbe accadere: l'utente inizia a digitare il nome, incluso uno spazio dopo di esso, quindi decide di eliminare i caratteri e lo spazio rimane, poiché non può "vederlo". – Rox

2

Non utilizzare foreach. Usa e discendi la lista (es. Inizia dalla fine), usando RemoveAt.

Quindi,

// 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

Utilizzare un per/while, o tmpClientList.RemoveAll(a => a.Name == txtboxClientName.Text). Come non hai specificato quale versione C# stai usando, ymmw.

+1

E quando limitato a 2.0, è solo un po 'più dettagliato: 'tmpClientList.RemoveAll (delegato (Client a) {return a.Name == txtboxClientName.Text;});' – Humberto

11

Spostarsi indietro nell'elenco ... in questo modo la rimozione di un elemento non influisce sull'elemento successivo.

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

} 
+0

bella soluzione semplice, grazie per la condivisione – qlf00n

11

In un List<T>, v'è un metodo RemoveAll che prende un delegato per indicare se rimuovere l'elemento. Si può usare in questo modo:

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

+1 Si noti che questo funziona solo con C# 3.0 e successivi. L'OP ha contrassegnato la domanda con le versioni 2, 3 e 4 :-) –

+1

@Jakob: Se l'OP non sta utilizzando C# 3 o più recente, possono chiamare 'RemoveAll' con la sintassi del delegato old-skool:' tmpCLientList.RemoveAll (delegato (Client cli) {return cli.Name! = txtboxClientName.Text;}); ' – LukeH

+0

Oh, giusto: pensavo che RemoveAll fosse un metodo di estensione. Mi dispiace per quello :-) –

1

È possibile creare un altro elenco con gli elementi che si desidera eliminare e iterare il nuovo elenco per rimuovere elementi dalla lista "txtboxClientName".

+0

Esatto, posso usare i metodi Contains() e Remove() sull'elenco delle copie, mentre sto scorrendo su quello originale. Grazie. – qlf00n

1

In realtà, foreach utilizza gli Enumeratori per iterare attraverso determinate Collezioni di articoli. Andando oltre il System.Collections.Generic.List<T> implementa il IEnumarable-Interface a provide a Class, che sa come iterare attraverso gli elementi della lista, vale a dire il Enumerator. Ora se si scorre su quella lista usando foreach l'Enumerator tiene traccia della posizione corrente, come raggiungere la posizione successiva e altre cose. La logica interna potrebbe essere qualcosa come memorizzare il numero di elementi in una variabile n e quindi accedere a tutti gli oggetti da 0 a n-1. Come si può notare se qualsiasi oggetto viene rimosso tra le fasi di iterazione, termineremo in un NullReferenceException quando l'Enumeratore tenta di consegnare l'ultimo oggetto della lista. Quindi, per prevenire eventuali errori di iterazione, non è possibile modificare la lista stessa durante Enumerazione.

Spero di essere stato in grado di dirlo almeno un po 'in modo completo. :-)

+0

grazie per informazioni molto precise, GTK come funziona internamente – qlf00n

Problemi correlati