在遍历列表时向列表中添加项目是否安全
本文关键字:列表 项目 是否 添加 安全 遍历 | 更新日期: 2023-09-27 18:30:11
我知道不能同时使用枚举器和修改List<T>
。添加或删除项将使枚举器无效(http://msdn.microsoft.com/en-us/library/system.collections.ienumerator(v=vs.110).aspx),因为内部数组将被重新分配(http://msdn.microsoft.com/en-us/library/3wcytfd1(v=vs.110).aspx).
- 即使
Count
小于Capacity
,它总是真的吗?(据我所知,在这种情况下,数组不会被重新分配,因此枚举器必须有效) - 为什么
Current
返回它设置为的元素,即使枚举器已经无效?(我的意思是,如果数组被重新分配…) - 重新分配是否保留了项目的原始顺序?我的意思是,如果某个项目的索引为n,那么在添加和项目后,它会有相同的索引吗?(MSDN说
Add
在列表末尾添加了一个对象)如果是这样,那么在常规的for
循环中运行列表并添加项目是安全的,假设循环只遍历每个项目一次,我是对的吗
即使
Count
小于Capacity
,它总是真的吗
这可能是真的,也可能不是真的。但是,您应该表现得好像它始终是真的一样,因为文档不会对此行为做出任何例外。
在每次更改列表的操作中,至少有一个List<T>
实现(来自Mono项目)总是通过递增存储在列表中的名为_version
的隐藏成员来使所有迭代器无效。当您获得迭代器(在.NET中称为Enumerator
)时,_version
的当前值存储在枚举器对象中。每次调用MoveNext
时,都会将存储的_version
与当前的_version
进行比较,当两者不匹配时会引发异常。
为什么
Current
返回它设置为的元素,即使枚举器已经无效?
因为Current
的值存储在迭代器中。虽然在修改集合时有充分的理由阻止您进一步迭代,但当迭代器有效时,允许您访问迭代器前进位置的值也是可以的。
重新分配是否保留了项目的原始顺序?
是的。这就是为什么即使在列表中添加或删除元素时,使用for
循环和索引遍历列表仍然是安全的。
-
内部数组不会在每次从列表中添加/删除项时重新分配,这不是枚举器无效的原因。这里有一个更好的理由:集合被修改了;枚举操作可能无法执行-为什么?。
简单地说,内部阵列在其容量耗尽时被重新分配,阵列的大小将增加一倍。某些集合还允许修剪内部数组,例如
List<T>.TrimExcess
-
为什么不呢?该对象仍然存在。
-
是
如果您想了解更多信息,请查看源代码,特别是EnsureCapacity
和List<T>.Enumerator
。
添加或删除项将使枚举器无效,因为内部阵列将被重新分配
这部分是正确的。添加、删除或插入项将使枚举器失效而不是,因为内部数组将被重新分配,但因为List<T>
在内部维护一个version
字段以跟踪已发生的更改。枚举器将使用版本字段查找自创建枚举器以来发生的任何新更新。
回答您的问题:
- 如果修改列表而不考虑"计数<容量",则枚举器无效,因为这无关紧要。重要的是版本字段
- 因为枚举器从列表中获取当前元素的副本
- 是的,重新分配保留订单
1:这并不总是真的,在实现中有一个bug。