It’s important to note that an enumerator does not have exclusive, thread-safe access to its collection.  Even when a collection is synchronized, other threads can still modify the collection.  Therefore, a collection’s contents can change while enumerating through it, which will cause the enumerator to throw an exception.  So there are three key ways to safely enumerate a collection:

1. Lock the Collection During Enumeration

To prevent changes to a collection while enumerating through it, you can lock the collection using its SyncRoot property.  Note that you can grow your own SyncRoot for collections that don’t have a SyncRoot property.  The downside to this approach is that large collections may be locked for long periods of time, resulting in poor performance or deadlocks.

ArrayList list = new ArrayList();
lock (list.SyncRoot)
{
    foreach (object obj in list)
    {
        // do something
    }
}

2. Export Collection Contents to an Array

The best way to guarantee thread-safety is to exclusively own the collection, and the easiest way to do this is to export the collection’s contents to an array.  The downside to this approach is the time and memory used to create a separate array.

ArrayList list = new ArrayList();
Array array = list.ToArray();
foreach (object obj in array)
{
    // do something
}

3. Catch Enumerator Exceptions

The final approach is simply to catch any exceptions and re-start the enumeration.  The downside to this approach is the enumeration could restart multiple times for oft-changing collections, and there may be cases where you do not want to repeat the enumeration.

ArrayList list = new ArrayList();
bool finished = false;
while (!finished)
{
    try
    {
        foreach (object obj in array)
        {
            // do something
        }
        finished = true;
    }
    catch (InvalidOperationException)
    {
        // collection changed
    }
}

Share and Enjoy:
  • Digg
  • Twitter
  • Facebook
  • Reddit
  • StumbleUpon
  • LinkedIn
  • Google Bookmarks
  • Slashdot