Wednesday, August 24, 2011

Collection was modified; enumeration operation may not execute.

This .Net error typically occurs when the underlying collection is modified during enumeration. For example if you remove items from the collection while enumerating the collection.

It can also happen when you're accessing a collection while adding to the collection. See if you can see the bug in the following code which is in the Menus accessor in a singleton object.

if (_Menus == null)
{
    lock (lockObj)
    {
        if (_Menus == null)
        {
            _Menus = new List<MenuItem>();
            _Menus.Add(new MenuItem
            {
                Link = "/mylink",
                AnchorText = "MyText",
                TitleText = "My Title"
            });
            // ... add more items
        }
    }
}
return _Menus;

Note above that we are correctly doing the double null check. Also, not visible in the code we have marked the _Menus item as volatile to prevent the compiler from removing the seemingly redundant double null check.

Here is the fixed code:

if (_Menus == null)
{
    lock (lockObj)
    {
        if (_Menus == null)
        {
            List<MenuItem> tempMenus = new List<MenuItem>();
            tempMenus.Add(new MenuItem
            {
                Link = "/mylink",
                AnchorText = "MyText",
                TitleText = "My Title"
            });
            // ... add more items
           _Menus = tempMenus;
        }
    }
}
return _Menus;

The solution, as demonstrated, is to create a locally scoped temporary collector and build that before assigning it to the _Menus variable. That way all other requests for this object will hold on the lock until this has completed building and then won't attempt to build it because it already exists as determined by the second null check.