错误信息: 集合已修改;可能无法执行枚举操作。
调用堆栈:
在 System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
在 System.Collections.Generic.Dictionary`2.Enumerator.MoveNext()
这个错误是怎么引发的?
我们具体分析一下Dictionary的内部实现。
public class Dictionary<TKey, TValue>
{
//字典的版本号
private int version;
public void Clear()
{
//执行这个操作后,版本号加一,版本发生变化
this.version++;
}
private void Insert(TKey key, TValue value, bool add)
{
//执行这个操作后,版本号加一,版本发生变化
this.version++;
}
public bool Remove(TKey key)
{
//执行这个操作后,版本号加一,版本发生变化
this.version++;
}
public void Add(TKey key, TValue value)
{
//执行这个操作后,版本号加一,版本发生变化
this.Insert(key, value, true);
}
public struct Enumerator
{
private Dictionary<TKey, TValue> dictionary;
//Enumerator的版本号
private int version;
internal Enumerator(Dictionary<TKey, TValue> dictionary)
{
this.dictionary = dictionary;
//初始化时,把当时dictionary.version传给Enumerator的version
this.version = dictionary.version;
}
public bool MoveNext()
{
//如果dictionary.version发生变化,就会抛出上面的异常
if (this.version != this.dictionary.version)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
}
}
通过分析源码可以知道,只要dictionary.version发生变化,在做foreach循环时,就会抛出上面的错误。
具体来说,在做foreach循环时,dictionary对象发生了Clear、Insert、Remove、Add操作时,就会引发上面的异常。
如果代码场景涉及到并发操作,推荐用并发字典ConcurrentDictionary,不要自己加锁控制并发。