views:

178

answers:

3

I have found out (in a hard way) that a collection that is being enumerated cannot be modified within "Foreach" statement

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

Now, the solution I came up with is to create a dummy collection of the same size that contains a dictionary key and enumerate over it to modify collection in question.

    private void InvalidateAuthenticatedNodes()
    {
        var dummy = new Dictionary<int, bool>(_AuthenticatedNodes.Count);
        foreach (var nodeId in _AuthenticatedNodes.Keys)
            dummy[nodeId] = false;

        foreach (var nodeId in dummy.Keys)
            _AuthenticatedNodes[nodeId] = false;

        ClearAuthenticatedDateTime();
    }

Above code worked fine; I was in process of refactoring above code to use a Func delegate to return a copy of keys as following

    private void InvalidateAuthenticatedNodes()
    {
        var getNodeIds = 
            new Func<Dictionary<int, bool>, IEnumerable<int>>(
                nodes => nodes.Select(node => node.Key));
        foreach (var nodeId in getNodeIds(_AuthenticatedNodes))
        {
            _AuthenticatedNodes[nodeId] = false;
        }

        ClearAuthenticatedDateTime();
    }

Unlike what I have expected, getNodeIds does not return a copy. Is there a way to return a copy instead?

*EDIT: Temporary Result before JaredPar's answer

Similar to JaredPar's answer but his was more concise and I went with his answer. But here is the similar result I came up with to share.

    private void InvalidateAuthenticatedNodes()
    {
        var getNodeIds = 
            new Func<Dictionary<int, bool>, IEnumerable<int>>(nodes => 
                nodes.Select(node => node.Key));
        foreach (var nodeId in getNodeIds(_AuthenticatedNodes).ToList())
        {
            _AuthenticatedNodes[nodeId] = false;
        }

        ClearAuthenticatedDateTime();
    }

*EDIT: Final Result (refined)

_AuthenticatedNodes.Keys.ToList().ForEach(
    nodeId => _AuthenticatedNodes[nodeId] = false);
+4  A: 

Just add a .ToList() to the end of the collection and it will automagically return a complete copy of the list.

foreach (var nodeId in _AuthenticatedNodes.Keys.ToList())
    ...
JaredPar
Thank you; That is the path I chose.
Sung Meister
+1  A: 

Instead of using a foreach, you could use a normal for. However, be careful when adding/removing items, it changes the indexes of the elements inside the collection.

GoodEnough
+1  A: 

Once you change an Enumerable class, your original enumerator may become invalid, thus the need to create a copy and make your modifications there.

Chris Ballance