运行此代码时:
var list = new List{ "foo", "bar", }; foreach (var l in list) { Console.WriteLine(l); list.Add("bar"); }
抛出异常:
System.InvalidOperationException:集合已被修改; 枚举操作可能无法执行.
当枚举器迭代该集合时,.NET如何知道集合被修改?在集合对象中是否有这样的标志?
A List
在整数变量中内部保存其"版本".对列表的每次修改(添加,删除,排序,清除......)都会将此版本增加一个.
现在,a的枚举器List
在初始化时会保存此版本号.在每次MoveNext()
迭代时,即在每次迭代时,它检查列表的版本号是否仍然等于保存的版本号.
这样,它可以检测何时在两次迭代之间修改列表.请注意,此实现会导致整数溢出的特殊错误:为什么此代码会抛出"Collection was modified",但是当我在它之前迭代某些东西时,它不会?.
似乎还有一个错误Sort(Comparison
,它不会增加版本号.这段代码:
var list = new List{ "foo", "bar", }; foreach (var l in list) { Console.WriteLine(l); list.Sort((x, y) => x.CompareTo(y)); }
打印:
foo foo
是的,典型的解决方案是标志,版本值等,例如,如果是 List
https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646
这是一个版本
private int _version;
例如
public bool MoveNext() { ... return MoveNextRare() } private bool MoveNextRare() { if (version != list._version) { ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion); }