tags:

views:

156

answers:

7

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 list

// tmpClientList is List<Client> type

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

Error: "Collection was modified; enumeration operation may not execute."

How can i remove items from the list, in some simple way, without saving indexes of these items in another list or array, and removing them in another place in the code. Tried also RemoveAt(index) but it's exactly the same situation, modifying when loop runs.

+1  A: 

The problem is that you are trying the modify the list in a foreach iteration. Replace that with a for and you should be ok.

Also, since you seem to be using user input for the name, consider cleaning up the input a bit, at least with a Trim() to remove extra white spaces. If you don't, 'John ' and 'John' will be two different things. Same for the initial != "" check.

Rox
you mean, that "" and " " would be the same, and i should trim the input in that situation too (when user types only white chars as input)?
dygi
@dygi: yes. removing white spaces leaves only the relevant information - which in this case is none. As for a case when this might happen: The user starts typing the name, including a space after it, then decides to delete the chars and the space remains, as he can't 'see' it.
Rox
+2  A: 

Don't use foreach. Use for and descend the list (i.e. start from the end), using RemoveAt.

So,

// 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);
    }
Michael Todd
+4  A: 

Either use a for/while loop, or tmpClientList.RemoveAll(a => a.Name == txtboxClientName.Text). As you didn't specify which c# version you are using, ymmw.

Femaref
And when confined to 2.0, it's just a little more verbose: `tmpClientList.RemoveAll(delegate(Client a) { return a.Name == txtboxClientName.Text; });`
Humberto
+10  A: 

Move backwards through the list.. that way removing an item does not affect the next item.

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

}
Jamiec
nice simple solution, thanks for sharing
dygi
+10  A: 

On a List<T>, there is a RemoveAll method that takes a delegate to indicate whether to remove the item. You can use it like this:

tmpCLientList.RemoveAll(cli => cli.Name != txtboxClientName.Text);
bdukes
+1 One should note that this only works for C# 3.0 and up. The OP tagged the question with versions 2, 3, and 4 :-)
Jakob Christensen
@Jakob: If the OP isn't using C#3 or newer then they can call `RemoveAll` with old-skool delegate syntax: `tmpCLientList.RemoveAll(delegate(Client cli) { return cli.Name != txtboxClientName.Text; });`
LukeH
Oh right - thought that RemoveAll was an extension method. Sorry about that :-)
Jakob Christensen
+1  A: 

You can create another list with the items you want to delete and iterate the new list to remove items from your "txtboxClientName" list.

VoodooChild
Right, i can use Contains() and Remove() methods on the copy list, while iterating over original one. Thanks.
dygi
+1  A: 

Actually, foreach uses Enumerators to iterate through given Item-Collections. Going further the System.Collections.Generic.List<T> implements the IEnumarable-Interface to provide a Class, that knows how to iterate through the items of the list, i.e. the Enumerator. Now if you iterate through that list by using foreach the Enumerator keeps track of the current position, how to reach the next position and some other stuff. The internal logic could be something like storing the number of items in a variable n and then access all objects from 0 to n-1. As you may notice if any object is removed between the iteration steps we shall end in a NullReferenceException when the Enumerator tries to deliver the last object of the list. So to prevent any iteration failures, the list itself is not allowed to be modified during Enumeration.

Hope I was able to state that out at least a little bit comprehensively. :-)

stan
thanks for very precise information, GTK how it works internally
dygi