集合中_version字段的作用及自定义可枚举集合相关疑问
_version Field in .NET Collections Great question! This is one of those under-the-hood details that keeps .NET collections reliable and helps catch bugs early. Let's tackle each of your questions clearly:
1. Why do enumerators need to check the version?
This ties directly into .NET's fail-fast enumeration mechanism. When you start enumerating a collection, the enumerator captures the current value of the collection's _version. If the collection gets modified mid-enumeration, the enumerator has no safe way to keep traversing—you might end up skipping elements, processing duplicates, hitting index out-of-bounds errors, or even encountering silent, hard-to-debug data inconsistencies.
By checking the _version on every MoveNext() call, the enumerator can immediately detect if the collection has changed since enumeration started. If versions don't match, it throws an InvalidOperationException—a loud, clear warning that prevents far worse bugs from slipping through.
2. When does the enumerator version mismatch with the collection's version?
Any operation that alters the structure of the collection will increment the _version field. Common examples include:
- Adding elements (e.g.,
List.Add(),Dictionary.Add()) - Removing elements (e.g.,
List.RemoveAt(),Dictionary.Remove()) - Clearing the entire collection (
Clear()) - Inserting elements at a specific position (
List.Insert()) - Resizing the underlying storage (like when a
Listhits its capacity and expands its internal array) - Sorting or rearranging elements in a way that changes the collection's order (e.g.,
List.Sort())
Important note: Modifying the properties of elements already in the collection does NOT increment _version—only changes that affect the collection's size, order, or underlying storage trigger a version bump.
3. Should I implement my own _version field when building a custom enumerable collection?
It depends on your collection's behavior:
- If your collection is immutable: No need. Since the collection can't be modified after creation, the version will never change, and enumerators will always be safe.
- If your collection is mutable and follows .NET conventions: Absolutely. Adding a
_versionfield (the name is a convention, feel free to use something else like_changeCount) ensures your enumerators have the same fail-fast reliability as built-in collections.
Here's a simplified example of how this works in practice:
public class MyCustomList<T> : IEnumerable<T> { private T[] _items; private int _count; private int _version; // Version tracking field public void Add(T item) { // Resize logic omitted for brevity _items[_count++] = item; _version++; // Increment on structure change } public IEnumerator<T> GetEnumerator() { return new MyEnumerator(this); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); private class MyEnumerator : IEnumerator<T> { private readonly MyCustomList<T> _list; private readonly int _enumeratorVersion; private int _currentIndex; public MyEnumerator(MyCustomList<T> list) { _list = list; _enumeratorVersion = list._version; // Capture version at enumeration start _currentIndex = -1; } public T Current => _list._items[_currentIndex]; object IEnumerator.Current => Current; public bool MoveNext() { // Check for collection modification if (_enumeratorVersion != _list._version) throw new InvalidOperationException("Collection was modified during enumeration."); _currentIndex++; return _currentIndex < _list._count; } public void Dispose() { } public void Reset() { } // Rarely used in modern code } }
This ensures anyone using your collection gets the same predictable, bug-resistant behavior they expect from .NET's built-in types.
内容的提问来源于stack exchange,提问作者KainDefiant

