Skip to content

Conversation

@stephentoub
Copy link
Member

ConcurrentBag's snapshot enumeration semantics are obtained by creating an array of the contents and then enumerating that array. This was done with a custom enumerator out of an abundance of caution about maintaining semantics for operations with undefined behavior, e.g. using Current after MoveNext returns false. We've since stopped trying to maintain bug-for-bug compatibility in such undefined areas. As such, this just deletes the custom enumerator and uses Array's. This not only reduces code but has better performance characteristics (though the whole ToArray as part of enumeration already dominates the enumeration costs).

ConcurrentBag's snapshot enumeration semantics are obtained by creating an array of the contents and then enumerating that array. This was done with a custom enumerator out of an abundance of caution about maintaining semantics for operations with undefined behavior, e.g. using Current after MoveNext returns false. We've since stopped trying to maintain bug-for-bug compatibility in such undefined areas. As such, this just deletes the custom enumerator and uses Array's. This not only reduces code but has better performance characteristics (though the whole ToArray as part of enumeration already dominates the enumeration costs).
Copilot AI review requested due to automatic review settings July 7, 2025 00:36
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR removes the custom Enumerator class from ConcurrentBag<T> and switches its GetEnumerator implementation to use the array’s built-in enumerator, reducing code and improving performance.

  • Swapped out new Enumerator(ToArray()) for ((IEnumerable<T>)ToArray()).GetEnumerator()
  • Deleted the custom Enumerator class
  • Updated tests to expect the new array-based enumeration semantics

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/libraries/System.Collections.Concurrent/tests/ConcurrentBagTests.cs Adjusted test overrides to reflect array enumerator behavior
src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs Changed GetEnumerator to use array enumerator and removed the custom class

@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-collections
See info in area-owners.md if you want to be subscribed.

@stephentoub stephentoub enabled auto-merge (squash) July 7, 2025 14:04
@stephentoub stephentoub merged commit a110fed into dotnet:main Jul 7, 2025
82 of 88 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Aug 7, 2025
@stephentoub stephentoub deleted the cbenumerator branch December 12, 2025 23:00
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants