迭代枚举器

时间:2017-01-10 10:21:54

标签: c# .net

运行此代码时:

var list = new List<string>
{
    "foo",
    "bar",
};

foreach (var l in list)
{
    Console.WriteLine(l);

    list.Add("bar");
}

抛出异常:

  

System.InvalidOperationException:修改了集合;枚举操作可能无法执行。

当枚举器迭代该集合时,.NET如何知道该集合已被修改?在集合对象中是否有这样的标志?

2 个答案:

答案 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;

this tutorial

这是一个版本

 public bool MoveNext() {
   ...
   return MoveNextRare()
 } 

 private bool MoveNextRare()
 {                
   if (version != list._version) {
     ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
 }

E.g。

{{1}}
相关问题