Konrad Viltersten
Konrad Viltersten

Reputation: 39078

Unexpected behavior for a System.Collections.IEnumerator object

I wanted to remove all elements in a collection and since I didn't see .RemoveAll or such I went with the code below.

int number = addressBook.Items.Count;
System.Collections.IEnumerator enumerator = ...
while (enumerator.MoveNext())
{
  target = enumerator.Current as Outlook.ContactItem;
  target.Delete();
}

However, I noticed that the number of remaining elements in the collection is roughly the half for each run of the program. My conclusion was that .Delete() skips to the next element by itself, meaning that .MoveNext() i nthe condition for the loop jumps to the elements after the next.

So I tried to reset the enumerator as follows.

int number = addressBook.Items.Count;
System.Collections.IEnumerator enumerator = ...
while (enumerator.MoveNext())
{
  target = enumerator.Current as Outlook.ContactItem;
  target.Delete();
  enumerator.Reset();
}

However, as I checked the .Count I saw that the number of elements remaining was still 1 after the last element being deleted and the enumerator being reset. And of course I got an exception thrown in my face.

What am I missing in this picture? I know it's not a bug because that would be reported and resolved eons ago...

Upvotes: 1

Views: 432

Answers (4)

devgeezer
devgeezer

Reputation: 4189

I expect that using the Enumerable.Reverse extension would a welcome improvement to while...Last().Delete() solution. Here's what that might look like:

foreach(var target in addressBook.Items
    .OfType<Outlook.ContactItem>()
    .Reverse())
{
    target.Delete();
}

I don't use Reverse that often; in fact, I don't recall ever using it in production code but I haven't had to inter-operate with Outlook either. The benefit here is that you're not repeatedly traversing the entirety of the list-remainder after each item deletion like the while...Last().Delete() method does. There may not be much (any?) difference in performance when the item lists are small, but if the traversal is expensive (and I imagine that it is since this likely comes down to COM iterop calls under the hood) or if the lists are large, then the performance difference could be significant. The only way to know for sure is to test/profile.

Upvotes: 1

Kevin Gosse
Kevin Gosse

Reputation: 39007

Two things.

  1. You should be able to delete all the items with an enumerator as long as you re-instantiate it after deleting each item. Using LINQ, it should look like:

    while (addressBook.Items.Count > 0)
    {
        addressBook.Items
            .OfType<Outlook.ContactItem>()
            .Last()
            .Delete();
    }
    
  2. According to MSDN, you actually have to delete the items starting with the last one: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook._contactitem.delete.aspx

Upvotes: 1

Mormegil
Mormegil

Reputation: 8071

IEnumerator can be used only as long as the underlying collection remains unchanged. As soon as it changes (e.g. by removing elements from it), the enumerator is irrecoverably invalidated.

You just cannot use one enumerator to browse a collection while modifying it, and Reset is not going to help with that. You just need to create a new enumerator every time. E.g. something like that might work:

while (addressBook.Items.Count > 0)
{
    foreach(Outlook.ContactItem target in ...)
    {
        target.Delete();
        break; // <-- !
    }
}

Upvotes: 3

Niranjan Singh
Niranjan Singh

Reputation: 18290

See Marc Gravell's Answer.

Reset is redundant; so much so that it is a requirement in the language spec for iterator blocks to throw an exception on Reset. The correct thing to do is simply dispose and release the old iterator, and call GetEnumerator again. Or better: avoid having to read it twice, since not all data is repeatable.

Refer the following links:

Can't add/remove items from a collection while foreach is iterating over it
When IEnumerator.Reset() method is called?

using IEnumerator to removing items

Hope this help..

Upvotes: 1

Related Questions