diff --git a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs index acc0f1f4d8445c..9ee2761b9cd88e 100644 --- a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs +++ b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs @@ -459,7 +459,7 @@ public void Clear() /// was called. The enumerator is safe to use /// concurrently with reads from and writes to the bag. /// - public IEnumerator GetEnumerator() => new Enumerator(ToArray()); + public IEnumerator GetEnumerator() => ((IEnumerable)ToArray()).GetEnumerator(); /// /// Returns an enumerator that iterates through the Provides an enumerator for the bag. - /// - /// The original implementation of ConcurrentBag used a as part of - /// the GetEnumerator implementation. That list was then changed to be an array, but array's - /// GetEnumerator has different behavior than does list's, in particular for the case where - /// Current is used after MoveNext returns false. To avoid any concerns around compatibility, - /// we use a custom enumerator rather than just returning array's. This enumerator provides - /// the essential elements of both list's and array's enumerators. - /// - private sealed class Enumerator : IEnumerator - { - private readonly T[] _array; - private T? _current; - private int _index; - - public Enumerator(T[] array) - { - Debug.Assert(array != null); - _array = array; - } - - public bool MoveNext() - { - if (_index < _array.Length) - { - _current = _array[_index++]; - return true; - } - - _index = _array.Length + 1; - return false; - } - - public T Current => _current!; - - object? IEnumerator.Current - { - get - { - if (_index == 0 || _index == _array.Length + 1) - { - throw new InvalidOperationException(SR.ConcurrentBag_Enumerator_EnumerationNotStartedOrAlreadyFinished); - } - return Current; - } - } - - public void Reset() - { - _index = 0; - _current = default; - } - - public void Dispose() { } - } } } diff --git a/src/libraries/System.Collections.Concurrent/tests/ConcurrentBagTests.cs b/src/libraries/System.Collections.Concurrent/tests/ConcurrentBagTests.cs index b76b283223aaef..41caa3244f8124 100644 --- a/src/libraries/System.Collections.Concurrent/tests/ConcurrentBagTests.cs +++ b/src/libraries/System.Collections.Concurrent/tests/ConcurrentBagTests.cs @@ -11,6 +11,8 @@ namespace System.Collections.Concurrent.Tests { public class ConcurrentBagTests : ProducerConsumerCollectionTests { + protected override bool Enumerator_Current_UndefinedOperation_Throws => true; + protected override bool Enumerator_Empty_UsesSingletonInstance => true; protected override IProducerConsumerCollection CreateProducerConsumerCollection() => new ConcurrentBag(); protected override IProducerConsumerCollection CreateProducerConsumerCollection(IEnumerable collection) => new ConcurrentBag(collection); protected override bool IsEmpty(IProducerConsumerCollection pcc) => ((ConcurrentBag)pcc).IsEmpty;