views:

1099

answers:

3

So, I have a bug to remove

foreach (XElement x in items.Elements("x")) 
{
    XElement result = webservice.method(x);

    if (/*condition based on values in result*/) 
    {
     x.Remove();
    }
}

The problem is that calling x.Remove() alters the foreach such that if there are two Elements("x"), and the first is removed, the loop doesn't get to the second x element.

So how should I be looping this? Or should this be rewritten another way?

A: 

Create a collection before the loop logic, add the elements to be removed to the new collection, then call the items.Remove on each element in the new collection.

Tom Anderson
This should work. I remember doing this. My answer is probably not good. I remember something about if you make changes to a list or something, it is a good idea to use for, but if you are just looping through without making any changes, foreach is fine. Is this correct?
Xaisoft
A: 

Try it without a for instead of the foreach.

Xaisoft
+3  A: 

I suspect that Linq may be able to help you out here as follows.

using System.Linq;

void foo()
{
    items.Elements("x")
         .Where(x => condition(webservice.method(x)))
         .Remove();
}

If that doesn't work (i.e. the internal enumerator is still invalidated), make a shallow copy of the selected elements and delete them as follows.

using System.Linq;

void foo()
{
    List xElements = items.Elements("x")
                          .Where(x => condition(webservice.method(x)))
                          .ToList();

    for (int i = xElements.Count; i > 0 xElements.Count; --i)
    {
        xElements[i].Remove();
    }
}
Steve Guidi
+1 Ideal situation if you are using .Net 3.5
Tom Anderson
The first code snippet worked for me. Great solution. +1
Alex York