运行此代码时:
var list = new List<string>
{
"foo",
"bar",
};
foreach (var l in list)
{
Console.WriteLine(l);
list.Add("bar");
}
抛出异常:
System.InvalidOperationException:修改了集合;枚举操作可能无法执行。
当枚举器迭代该集合时,.NET如何知道该集合已被修改?在集合对象中是否有这样的标志?
答案 0 :(得分:7)
List<T>
内部将“version”保存在整数变量中。对列表的每次修改(添加,删除,排序,清除......)都会将此版本增加一个。
现在,List<T>
的枚举器在初始化时会保存此版本号。在每MoveNext()
次,即每次迭代时,它会检查列表的版本号是否仍然等于保存的版本号。
这样它可以检测何时在两次迭代之间修改列表。请注意,此实现会导致整数溢出的特殊错误:Why this code throws 'Collection was modified', but when I iterate something before it, it doesn't?。
似乎还有一个关于Sort(Comparison<T> comparison)
的错误,它不会增加版本号。这段代码:
var list = new List<string>
{
"foo",
"bar",
};
foreach (var l in list)
{
Console.WriteLine(l);
list.Sort((x, y) => x.CompareTo(y));
}
打印:
foo
foo
答案 1 :(得分:5)
是的,典型的解决方案是标志,版本值等,例如如果是 private int _version;
这是一个版本
public bool MoveNext() {
...
return MoveNextRare()
}
private bool MoveNextRare()
{
if (version != list._version) {
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
E.g。
{{1}}