简体   繁体   English

在迭代它时将项添加到List是否安全

[英]Is it safe to add items to the List while iterating through it

I understand that one cannot use an enumerator and make amendments to List<T> at the same time. 我知道不能使用枚举器并同时修改List<T> Adding or removing an item will invalidate the enumerator( http://msdn.microsoft.com/en-us/library/system.collections.ienumerator(v=vs.110).aspx ), since the internal array will be reallocated( http://msdn.microsoft.com/en-us/library/3wcytfd1(v=vs.110).aspx ). 添加或删除项目将使枚举器无效( 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 )。

  1. Is it always true, even if Count is less than Capacity ?(As far as I understand in this case the array won't be reallocated, so the enumerator has to be valid); 是否总是如此,即使Count小于Capacity ?(据我所知,在这种情况下,数组不会被重新分配,因此枚举器必须有效);
  2. Why Current returns the element that it is set to, even if the enumerator is already invalidated?(I mean, if the array was reallocated...); 为什么Current返回它所设置的元素,即使枚举器已经失效?(我的意思是,如果数组被重新分配...);
  3. Does reallocation preservers the original order of the items? 重新分配是否保留了项目的原始顺序? I mean if some item has index of n, will it have the same index after adding and item?(MSDN says that Add adds an object to the end of the list) If so, it is safe to run through a list in a regular for loop and to add the items assuming that the loop will iterate through each item only once, am I correct? 我的意思是如果某个项目的索引为n,在添加和项目后它是否会有相同的索引?(MSDN说Add将一个对象Add到列表的末尾)如果是这样,可以安全地运行常规列表for循环并添加项目,假设循环只迭代每个项目一次,我是否正确?

Is it always true, even if Count is less than Capacity 是否总是如此,即使Count小于Capacity

This may or may not be true. 这可能是也可能不是。 However, you should act as if it is always true, because the documentation does not make any exceptions for this behavior. 但是,您应该表现得总是如此,因为文档不会对此行为做出任何例外。

At least one implementation of List<T> (from the Mono project) always invalidates all iterators by incrementing a hidden member called _version which is stored inside the list, in every operation that changes the list. List<T> (来自Mono项目)的至少一个实现总是通过在每个更改列表的操作中递增存储在列表内的名为_version的隐藏成员来使所有迭代器无效。 When you obtain an iterator (which is called Enumerator in .NET) the current value of _version is stored inside the enumerator object. 获取迭代器(在.NET中称为Enumerator )时, _version的当前值存储在枚举器对象中。 Every time you call MoveNext , the stored _version is compared to the current _version , and an exception is thrown when the two do not match. 每次调用MoveNext ,都会将存储的_version与当前的_version进行比较,并在两者不匹配时抛出异常。

Why Current returns the element that it is set to, even if the enumerator is already invalidated? 为什么Current返回它设置的元素,即使枚举器已经失效?

Because the value of Current is stored in the iterator. 因为Current的值存储在迭代器中。 While there is a good reason to stop you from iterating further when the collection has been modified, it is fine to let you access the value at the position to which you advanced the iterator when it has been valid. 虽然有一个很好的理由阻止你在修改集合时进一步迭代,但是可以让你在迭代器有效的位置访问该位置的值。

Does reallocation preservers the original order of the items? 重新分配是否保留了项目的原始顺序?

Yes. 是。 That is why traversing a list with a for loop and an index remains safe even when you add or remove elements from your list. 这就是为什么即使在列表中添加或删除元素,遍历带有for循环和索引的列表仍然是安全的。

  1. The internal array is not reallocated every time items are added/removed from the list, and that's not the reason why the enumerator is invalidated. 每次从列表中添加/删除项目时都不会重新分配内部数组,这也不是枚举器失效的原因。 Here's a better reason: Collection was modified; 这是一个更好的理由: 收集被修改; enumeration operation may not execute - why? 枚举操作可能无法执行 - 为什么? .

    To put it simply, the internal array is reallocated when its capacity is exhausted, and the array's size will be doubled. 简单地说,内部阵列在其容量耗尽时重新分配,并且阵列的大小将加倍。 Some collections also allow you to prune the internal array, eg, List<T>.TrimExcess 某些集合还允许您修剪内部数组,例如List<T>.TrimExcess

  2. Why not? 为什么不? The object still exists. 该对象仍然存在。

  3. Yes

Take a look at the source code , particularly at EnsureCapacity and List<T>.Enumerator if you want to know more. 如果您想了解更多信息,请查看源代码 ,特别是在EnsureCapacityList<T>.Enumerator

Adding or removing an item will invalidate the enumerator, since the internal array will be reallocated 添加或删除项将使枚举器无效,因为将重新分配内部数组

This is partially correct. 这部分是正确的。 Adding, removing or inserting items will invalidate the enumerator not because internal array will be reallocated but because List<T> maintains a version field internally to track the changes that has happened. 添加,删除或插入项不会失效枚举因为内部阵列将被重新分配,但是因为List<T>维护version字段内部来跟踪已经发生的变化。 Enumerator will use the version field to find any new updates has happened since enumerator was created. 枚举器将使用version字段查找自枚举器创建以来发生的任何新更新。

To answer your questions: 回答你的问题:

  1. Enumerator is not valid [ 1 ] if you modify the list irrespective of the "Count < Capacity", because it doesn't matter. 如果您修改列表而不考虑“Count <Capacity”,则枚举器无效[ 1 ] ,因为它无关紧要。 What matters is the version field. 重要的是版本字段。
  2. Because enumerator takes a copy of current element from the List. 因为枚举器从List中获取当前元素的副本。
  3. Yes re allocation preserves the order. 是重新分配保留订单。

1: It is not always true , there is a bug in the implementation. 1: 并非总是如此 ,实施中存在错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM