diff --git a/src/libraries/Common/src/System/Collections/Generic/EnumerableHelpers.cs b/src/libraries/Common/src/System/Collections/Generic/EnumerableHelpers.cs
index b8646e3e878a5d..f73a2d3193f32f 100644
--- a/src/libraries/Common/src/System/Collections/Generic/EnumerableHelpers.cs
+++ b/src/libraries/Common/src/System/Collections/Generic/EnumerableHelpers.cs
@@ -8,6 +8,10 @@ namespace System.Collections.Generic
///
internal static partial class EnumerableHelpers
{
+ /// Gets an enumerator singleton for an empty collection.
+ internal static IEnumerator GetEmptyEnumerator() =>
+ ((IEnumerable)Array.Empty()).GetEnumerator();
+
/// Converts an enumerable to an array using the same logic as List{T}.
/// The enumerable to convert.
/// The number of items stored in the resulting array, 0-indexed.
diff --git a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs
index 44e28ea3ecd8c0..22f3912b65e7dd 100644
--- a/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs
+++ b/src/libraries/Common/tests/System/Collections/IDictionary.Generic.Tests.cs
@@ -421,7 +421,7 @@ public void IDictionary_Generic_Keys_Enumeration_ParentDictionaryModifiedInvalid
ICollection keys = dictionary.Keys;
IEnumerator keysEnum = keys.GetEnumerator();
dictionary.Add(GetNewKey(dictionary), CreateTValue(3432));
- if (IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified)
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified)
{
Assert.Throws(() => keysEnum.MoveNext());
Assert.Throws(() => keysEnum.Reset());
@@ -528,7 +528,7 @@ public void IDictionary_Generic_Values_Enumeration_ParentDictionaryModifiedInval
ICollection values = dictionary.Values;
IEnumerator valuesEnum = values.GetEnumerator();
dictionary.Add(GetNewKey(dictionary), CreateTValue(3432));
- if (IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified)
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified)
{
Assert.Throws(() => valuesEnum.MoveNext());
Assert.Throws(() => valuesEnum.Reset());
diff --git a/src/libraries/Common/tests/System/Collections/IDictionary.NonGeneric.Tests.cs b/src/libraries/Common/tests/System/Collections/IDictionary.NonGeneric.Tests.cs
index 944d067300fb65..adca2780d96d5a 100644
--- a/src/libraries/Common/tests/System/Collections/IDictionary.NonGeneric.Tests.cs
+++ b/src/libraries/Common/tests/System/Collections/IDictionary.NonGeneric.Tests.cs
@@ -392,7 +392,7 @@ public void IDictionary_NonGeneric_Keys_Enumeration_ParentDictionaryModifiedInva
ICollection keys = dictionary.Keys;
IEnumerator keysEnum = keys.GetEnumerator();
dictionary.Add(GetNewKey(dictionary), CreateTValue(3432));
- if (IDictionary_NonGeneric_Keys_Values_ParentDictionaryModifiedInvalidates)
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_NonGeneric_Keys_Values_ParentDictionaryModifiedInvalidates)
{
Assert.Throws(() => keysEnum.MoveNext());
Assert.Throws(() => keysEnum.Reset());
@@ -487,7 +487,7 @@ public virtual void IDictionary_NonGeneric_Values_Enumeration_ParentDictionaryMo
ICollection values = dictionary.Values;
IEnumerator valuesEnum = values.GetEnumerator();
dictionary.Add(GetNewKey(dictionary), CreateTValue(3432));
- if (IDictionary_NonGeneric_Keys_Values_ParentDictionaryModifiedInvalidates)
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : IDictionary_NonGeneric_Keys_Values_ParentDictionaryModifiedInvalidates)
{
Assert.Throws(() => valuesEnum.MoveNext());
Assert.Throws(() => valuesEnum.Reset());
diff --git a/src/libraries/Common/tests/System/Collections/IEnumerable.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IEnumerable.Generic.Tests.cs
index c23f9ca2542478..a71f72e6cc6fa9 100644
--- a/src/libraries/Common/tests/System/Collections/IEnumerable.Generic.Tests.cs
+++ b/src/libraries/Common/tests/System/Collections/IEnumerable.Generic.Tests.cs
@@ -85,6 +85,20 @@ public abstract partial class IEnumerable_Generic_Tests : TestBase
///
protected virtual bool Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException => true;
+ ///
+ /// When calling MoveNext or Reset after modification of an empty enumeration, the resulting behavior is
+ /// undefined. Tests are included to cover two behavioral scenarios:
+ /// - Throwing an InvalidOperationException
+ /// - Execute MoveNext or Reset.
+ ///
+ /// If this property is set to true, the tests ensure that the exception is thrown. The default value is
+ /// .
+ ///
+ protected virtual bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException;
+
+ /// Whether the enumerator returned from GetEnumerator is a singleton instance when the collection is empty.
+ protected virtual bool Enumerator_Empty_UsesSingletonInstance => false;
+
///
/// Specifies whether this IEnumerable follows some sort of ordering pattern.
///
@@ -302,6 +316,30 @@ private void VerifyEnumerator(
#region GetEnumerator()
+ [Fact]
+ public void IEnumerable_NonGeneric_GetEnumerator_EmptyCollection_UsesSingleton()
+ {
+ IEnumerable enumerable = GenericIEnumerableFactory(0);
+
+ IEnumerator enumerator1 = enumerable.GetEnumerator();
+ try
+ {
+ IEnumerator enumerator2 = enumerable.GetEnumerator();
+ try
+ {
+ Assert.Equal(Enumerator_Empty_UsesSingletonInstance, ReferenceEquals(enumerator1, enumerator2));
+ }
+ finally
+ {
+ if (enumerator2 is IDisposable d2) d2.Dispose();
+ }
+ }
+ finally
+ {
+ if (enumerator1 is IDisposable d1) d1.Dispose();
+ }
+ }
+
[Theory]
[MemberData(nameof(ValidCollectionSizes))]
public void IEnumerable_Generic_GetEnumerator_NoExceptionsWhileGetting(int count)
@@ -381,7 +419,7 @@ public void IEnumerable_Generic_Enumerator_MoveNext_ModifiedBeforeEnumeration_Th
{
if (ModifyEnumerable(enumerable))
{
- if (Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
{
Assert.Throws(() => enumerator.MoveNext());
}
@@ -427,7 +465,7 @@ public void IEnumerable_Generic_Enumerator_MoveNext_ModifiedDuringEnumeration_Th
enumerator.MoveNext();
if (ModifyEnumerable(enumerable))
{
- if (Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
{
Assert.Throws(() => enumerator.MoveNext());
}
@@ -471,7 +509,7 @@ public void IEnumerable_Generic_Enumerator_MoveNext_ModifiedAfterEnumeration_Thr
while (enumerator.MoveNext()) ;
if (ModifyEnumerable(enumerable))
{
- if (Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
{
Assert.Throws(() => enumerator.MoveNext());
}
@@ -602,8 +640,7 @@ public void IEnumerable_Generic_Enumerator_Current_BeforeFirstMoveNext_Undefined
IEnumerable enumerable = GenericIEnumerableFactory(count);
using (IEnumerator enumerator = enumerable.GetEnumerator())
{
- if (Enumerator_Current_UndefinedOperation_Throws ||
- (count == 0 && Enumerator_Empty_Current_UndefinedOperation_Throws))
+ if (count == 0 ? Enumerator_Empty_Current_UndefinedOperation_Throws : Enumerator_Current_UndefinedOperation_Throws)
Assert.Throws(() => enumerator.Current);
else
current = enumerator.Current;
@@ -619,8 +656,7 @@ public void IEnumerable_Generic_Enumerator_Current_AfterEndOfEnumerable_Undefine
using (IEnumerator enumerator = enumerable.GetEnumerator())
{
while (enumerator.MoveNext()) ;
- if (Enumerator_Current_UndefinedOperation_Throws ||
- (count == 0 && Enumerator_Empty_Current_UndefinedOperation_Throws))
+ if (count == 0 ? Enumerator_Empty_Current_UndefinedOperation_Throws : Enumerator_Current_UndefinedOperation_Throws)
Assert.Throws(() => enumerator.Current);
else
current = enumerator.Current;
@@ -639,7 +675,7 @@ public void IEnumerable_Generic_Enumerator_Current_ModifiedDuringEnumeration_Und
{
if (ModifyEnumerable(enumerable))
{
- if (Enumerator_Current_UndefinedOperation_Throws)
+ if (count == 0 ? Enumerator_Empty_Current_UndefinedOperation_Throws : Enumerator_Current_UndefinedOperation_Throws)
Assert.Throws(() => enumerator.Current);
else
current = enumerator.Current;
@@ -694,7 +730,7 @@ public void IEnumerable_Generic_Enumerator_Reset_ModifiedBeforeEnumeration_Throw
{
if (ModifyEnumerable(enumerable))
{
- if (Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
{
Assert.Throws(() => enumerator.Reset());
}
@@ -737,7 +773,7 @@ public void IEnumerable_Generic_Enumerator_Reset_ModifiedDuringEnumeration_Throw
enumerator.MoveNext();
if (ModifyEnumerable(enumerable))
{
- if (Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
{
Assert.Throws(() => enumerator.Reset());
}
@@ -781,7 +817,7 @@ public void IEnumerable_Generic_Enumerator_Reset_ModifiedAfterEnumeration_Throws
while (enumerator.MoveNext()) ;
if (ModifyEnumerable(enumerable))
{
- if (Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
{
Assert.Throws(() => enumerator.Reset());
}
diff --git a/src/libraries/Common/tests/System/Collections/IEnumerable.NonGeneric.Tests.cs b/src/libraries/Common/tests/System/Collections/IEnumerable.NonGeneric.Tests.cs
index 5760cbef9069c1..a441cf4d787330 100644
--- a/src/libraries/Common/tests/System/Collections/IEnumerable.NonGeneric.Tests.cs
+++ b/src/libraries/Common/tests/System/Collections/IEnumerable.NonGeneric.Tests.cs
@@ -60,6 +60,31 @@ public abstract partial class IEnumerable_NonGeneric_Tests : TestBase
///
protected virtual bool Enumerator_Current_UndefinedOperation_Throws => false;
+ ///
+ /// When calling MoveNext or Reset after modification of the enumeration, the resulting behavior is
+ /// undefined. Tests are included to cover two behavioral scenarios:
+ /// - Throwing an InvalidOperationException
+ /// - Execute MoveNext or Reset.
+ ///
+ /// If this property is set to true, the tests ensure that the exception is thrown. The default value is
+ /// true.
+ ///
+ protected virtual bool Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException => true;
+
+ ///
+ /// When calling MoveNext or Reset after modification of an empty enumeration, the resulting behavior is
+ /// undefined. Tests are included to cover two behavioral scenarios:
+ /// - Throwing an InvalidOperationException
+ /// - Execute MoveNext or Reset.
+ ///
+ /// If this property is set to true, the tests ensure that the exception is thrown. The default value is
+ /// .
+ ///
+ protected virtual bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException;
+
+ /// Whether the enumerator returned from GetEnumerator is a singleton instance when the collection is empty.
+ protected virtual bool Enumerator_Empty_UsesSingletonInstance => false;
+
///
/// Whether the collection can be serialized.
///
@@ -83,6 +108,30 @@ protected enum EnumerableOrder
#region GetEnumerator()
+ [Fact]
+ public void IEnumerable_NonGeneric_GetEnumerator_EmptyCollection_UsesSingleton()
+ {
+ IEnumerable enumerable = NonGenericIEnumerableFactory(0);
+
+ IEnumerator enumerator1 = enumerable.GetEnumerator();
+ try
+ {
+ IEnumerator enumerator2 = enumerable.GetEnumerator();
+ try
+ {
+ Assert.Equal(Enumerator_Empty_UsesSingletonInstance, ReferenceEquals(enumerator1, enumerator2));
+ }
+ finally
+ {
+ if (enumerator2 is IDisposable d2) d2.Dispose();
+ }
+ }
+ finally
+ {
+ if (enumerator1 is IDisposable d1) d1.Dispose();
+ }
+ }
+
[Theory]
[MemberData(nameof(ValidCollectionSizes))]
public void IEnumerable_NonGeneric_GetEnumerator_NoExceptionsWhileGetting(int count)
@@ -141,7 +190,16 @@ public void IEnumerable_NonGeneric_Enumerator_MoveNext_ModifiedBeforeEnumeration
IEnumerable enumerable = NonGenericIEnumerableFactory(count);
IEnumerator enumerator = enumerable.GetEnumerator();
if (ModifyEnumerable(enumerable))
- Assert.Throws(() => enumerator.MoveNext());
+ {
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ {
+ Assert.Throws(() => enumerator.MoveNext());
+ }
+ else
+ {
+ _ = enumerator.MoveNext();
+ }
+ }
});
}
@@ -153,10 +211,21 @@ public void IEnumerable_NonGeneric_Enumerator_MoveNext_ModifiedDuringEnumeration
{
IEnumerable enumerable = NonGenericIEnumerableFactory(count);
IEnumerator enumerator = enumerable.GetEnumerator();
+
for (int i = 0; i < count / 2; i++)
enumerator.MoveNext();
+
if (ModifyEnumerable(enumerable))
- Assert.Throws(() => enumerator.MoveNext());
+ {
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ {
+ Assert.Throws(() => enumerator.MoveNext());
+ }
+ else
+ {
+ enumerator.MoveNext();
+ }
+ }
});
}
@@ -170,7 +239,16 @@ public void IEnumerable_NonGeneric_Enumerator_MoveNext_ModifiedAfterEnumeration_
IEnumerator enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext()) ;
if (ModifyEnumerable(enumerable))
- Assert.Throws(() => enumerator.MoveNext());
+ {
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ {
+ Assert.Throws(() => enumerator.MoveNext());
+ }
+ else
+ {
+ _ = enumerator.MoveNext();
+ }
+ }
});
}
@@ -290,7 +368,16 @@ public void IEnumerable_NonGeneric_Enumerator_Reset_ModifiedBeforeEnumeration_Th
IEnumerable enumerable = NonGenericIEnumerableFactory(count);
IEnumerator enumerator = enumerable.GetEnumerator();
if (ModifyEnumerable(enumerable))
- Assert.Throws(() => enumerator.Reset());
+ {
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ {
+ Assert.Throws(() => enumerator.Reset());
+ }
+ else
+ {
+ enumerator.Reset();
+ }
+ }
});
}
@@ -302,10 +389,21 @@ public void IEnumerable_NonGeneric_Enumerator_Reset_ModifiedDuringEnumeration_Th
{
IEnumerable enumerable = NonGenericIEnumerableFactory(count);
IEnumerator enumerator = enumerable.GetEnumerator();
+
for (int i = 0; i < count / 2; i++)
enumerator.MoveNext();
+
if (ModifyEnumerable(enumerable))
- Assert.Throws(() => enumerator.Reset());
+ {
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ {
+ Assert.Throws(() => enumerator.Reset());
+ }
+ else
+ {
+ enumerator.Reset();
+ }
+ }
});
}
@@ -319,7 +417,16 @@ public void IEnumerable_NonGeneric_Enumerator_Reset_ModifiedAfterEnumeration_Thr
IEnumerator enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext()) ;
if (ModifyEnumerable(enumerable))
- Assert.Throws(() => enumerator.Reset());
+ {
+ if (count == 0 ? Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException : Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException)
+ {
+ Assert.Throws(() => enumerator.Reset());
+ }
+ else
+ {
+ enumerator.Reset();
+ }
+ }
});
}
diff --git a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs
index 820ea6407ab755..44f67e0ca24f83 100644
--- a/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs
+++ b/src/libraries/Common/tests/System/Collections/IList.Generic.Tests.cs
@@ -614,7 +614,7 @@ public void IList_Generic_CurrentAtEnd_AfterAdd(int count)
while (enumerator.MoveNext()) ; // Go to end of enumerator
T current = default(T);
- if (Enumerator_Current_UndefinedOperation_Throws)
+ if (count == 0 ? Enumerator_Empty_Current_UndefinedOperation_Throws : Enumerator_Current_UndefinedOperation_Throws)
{
Assert.Throws(() => enumerator.Current); // enumerator.Current should fail
}
@@ -630,7 +630,7 @@ public void IList_Generic_CurrentAtEnd_AfterAdd(int count)
{
collection.Add(CreateT(seed++));
- if (Enumerator_Current_UndefinedOperation_Throws)
+ if (count == 0 ? Enumerator_Empty_Current_UndefinedOperation_Throws : Enumerator_Current_UndefinedOperation_Throws)
{
Assert.Throws(() => enumerator.Current); // enumerator.Current should fail
}
diff --git a/src/libraries/System.Collections.Concurrent/tests/ConcurrentDictionary/ConcurrentDictionary.Generic.Tests.cs b/src/libraries/System.Collections.Concurrent/tests/ConcurrentDictionary/ConcurrentDictionary.Generic.Tests.cs
index 1ec173dbc640db..f488444133a303 100644
--- a/src/libraries/System.Collections.Concurrent/tests/ConcurrentDictionary/ConcurrentDictionary.Generic.Tests.cs
+++ b/src/libraries/System.Collections.Concurrent/tests/ConcurrentDictionary/ConcurrentDictionary.Generic.Tests.cs
@@ -189,6 +189,7 @@ public abstract class ConcurrentDictionary_Generic_Tests : IDictio
protected override IEnumerable GetModifyEnumerables(ModifyOperation operations) => new List();
+ protected override bool Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override bool IDictionary_Generic_Keys_Values_Enumeration_ThrowsInvalidOperation_WhenParentModified => false;
protected override bool IDictionary_Generic_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection => false;
diff --git a/src/libraries/System.Collections.Concurrent/tests/ConcurrentDictionary/ConcurrentDictionary.NonGeneric.Tests.cs b/src/libraries/System.Collections.Concurrent/tests/ConcurrentDictionary/ConcurrentDictionary.NonGeneric.Tests.cs
index 9df2101c84a4e9..b7e63f51f402f9 100644
--- a/src/libraries/System.Collections.Concurrent/tests/ConcurrentDictionary/ConcurrentDictionary.NonGeneric.Tests.cs
+++ b/src/libraries/System.Collections.Concurrent/tests/ConcurrentDictionary/ConcurrentDictionary.NonGeneric.Tests.cs
@@ -38,6 +38,8 @@ protected override object CreateTKey(int seed)
protected override bool Enumerator_Current_UndefinedOperation_Throws => false;
+ protected override bool Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
+
protected override bool IDictionary_NonGeneric_Keys_Values_ModifyingTheDictionaryUpdatesTheCollection => false;
protected override bool ICollection_NonGeneric_SupportsSyncRoot => false;
diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableArray/ImmutableArray.Generic.Tests.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableArray/ImmutableArray.Generic.Tests.cs
index f1373db05c6423..a21bcf815d4f67 100644
--- a/src/libraries/System.Collections.Immutable/tests/ImmutableArray/ImmutableArray.Generic.Tests.cs
+++ b/src/libraries/System.Collections.Immutable/tests/ImmutableArray/ImmutableArray.Generic.Tests.cs
@@ -20,6 +20,7 @@ public abstract class ImmutableArray_Generic_Tests : IList_Generic_Tests
protected override bool IsReadOnly => true;
protected override IEnumerable GetModifyEnumerables(ModifyOperation operations) => new List();
protected override Type IList_Generic_Item_InvalidIndex_ThrowType => typeof(IndexOutOfRangeException);
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
protected override IList GenericIListFactory() => GenericIListFactory(0);
diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableArray/ImmutableArray.NonGeneric.Tests.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableArray/ImmutableArray.NonGeneric.Tests.cs
index 0d9410cedca93e..fabefa12d4cd47 100644
--- a/src/libraries/System.Collections.Immutable/tests/ImmutableArray/ImmutableArray.NonGeneric.Tests.cs
+++ b/src/libraries/System.Collections.Immutable/tests/ImmutableArray/ImmutableArray.NonGeneric.Tests.cs
@@ -15,6 +15,7 @@ public class ImmutableArray_NonGeneric_Tests : IList_NonGeneric_Tests
protected override Type IList_NonGeneric_Item_InvalidIndex_ThrowType => typeof(IndexOutOfRangeException);
protected override IEnumerable GetModifyEnumerables(ModifyOperation operations) => new List();
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
protected override Type ICollection_NonGeneric_CopyTo_TwoDimensionArray_ThrowType => typeof(RankException);
diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/LinkedList.cs b/src/libraries/System.Collections/src/System/Collections/Generic/LinkedList.cs
index 0e99312eba2895..a50dce3b158946 100644
--- a/src/libraries/System.Collections/src/System/Collections/Generic/LinkedList.cs
+++ b/src/libraries/System.Collections/src/System/Collections/Generic/LinkedList.cs
@@ -283,15 +283,11 @@ public void CopyTo(T[] array, int index)
return null;
}
- public Enumerator GetEnumerator()
- {
- return new Enumerator(this);
- }
+ public Enumerator GetEnumerator() => new Enumerator(this);
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
+ IEnumerator IEnumerable.GetEnumerator() =>
+ Count == 0 ? EnumerableHelpers.GetEmptyEnumerator() :
+ GetEnumerator();
public bool Remove(T value)
{
@@ -497,10 +493,7 @@ void ICollection.CopyTo(Array array, int index)
}
}
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator();
public struct Enumerator : IEnumerator, IEnumerator, ISerializable, IDeserializationCallback
{
diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs b/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs
index 67f2ae3c176d13..e8d8221641cd2a 100644
--- a/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs
+++ b/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs
@@ -961,9 +961,11 @@ void IEnumerator.Reset()
/// An for the .
public Enumerator GetEnumerator() => new Enumerator(_queue);
- IEnumerator<(TElement Element, TPriority Priority)> IEnumerable<(TElement Element, TPriority Priority)>.GetEnumerator() => GetEnumerator();
+ IEnumerator<(TElement Element, TPriority Priority)> IEnumerable<(TElement Element, TPriority Priority)>.GetEnumerator() =>
+ _queue.Count == 0 ? EnumerableHelpers.GetEmptyEnumerator<(TElement Element, TPriority Priority)>() :
+ GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<(TElement Element, TPriority Priority)>)this).GetEnumerator();
}
}
}
diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/SortedDictionary.cs b/src/libraries/System.Collections/src/System/Collections/Generic/SortedDictionary.cs
index 08335221c4011a..64d745a778fcef 100644
--- a/src/libraries/System.Collections/src/System/Collections/Generic/SortedDictionary.cs
+++ b/src/libraries/System.Collections/src/System/Collections/Generic/SortedDictionary.cs
@@ -247,15 +247,11 @@ public void CopyTo(KeyValuePair[] array, int index)
_set.CopyTo(array, index);
}
- public Enumerator GetEnumerator()
- {
- return new Enumerator(this, Enumerator.KeyValuePair);
- }
+ public Enumerator GetEnumerator() => new Enumerator(this, Enumerator.KeyValuePair);
- IEnumerator> IEnumerable>.GetEnumerator()
- {
- return new Enumerator(this, Enumerator.KeyValuePair);
- }
+ IEnumerator> IEnumerable>.GetEnumerator() =>
+ Count == 0 ? EnumerableHelpers.GetEmptyEnumerator>() :
+ GetEnumerator();
public bool Remove(TKey key)
{
@@ -389,10 +385,7 @@ private static bool IsCompatibleKey(object key)
return (key is TKey);
}
- IDictionaryEnumerator IDictionary.GetEnumerator()
- {
- return new Enumerator(this, Enumerator.DictEntry);
- }
+ IDictionaryEnumerator IDictionary.GetEnumerator() => new Enumerator(this, Enumerator.DictEntry);
void IDictionary.Remove(object key)
{
@@ -412,10 +405,7 @@ object ICollection.SyncRoot
get { return ((ICollection)_set).SyncRoot; }
}
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(this, Enumerator.KeyValuePair);
- }
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable>)this).GetEnumerator();
public struct Enumerator : IEnumerator>, IDictionaryEnumerator
{
@@ -541,20 +531,13 @@ public KeyCollection(SortedDictionary dictionary)
_dictionary = dictionary;
}
- public Enumerator GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ public Enumerator GetEnumerator() => new Enumerator(_dictionary);
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ IEnumerator IEnumerable.GetEnumerator() =>
+ Count == 0 ? EnumerableHelpers.GetEmptyEnumerator() :
+ GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator();
public void CopyTo(TKey[] array, int index)
{
@@ -709,20 +692,13 @@ public ValueCollection(SortedDictionary dictionary)
_dictionary = dictionary;
}
- public Enumerator GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ public Enumerator GetEnumerator() => new Enumerator(_dictionary);
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ IEnumerator IEnumerable.GetEnumerator() =>
+ Count == 0 ? EnumerableHelpers.GetEmptyEnumerator() :
+ GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator();
public void CopyTo(TValue[] array, int index)
{
diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/SortedList.cs b/src/libraries/System.Collections/src/System/Collections/Generic/SortedList.cs
index 3204094bf71ecd..167e1be161f027 100644
--- a/src/libraries/System.Collections/src/System/Collections/Generic/SortedList.cs
+++ b/src/libraries/System.Collections/src/System/Collections/Generic/SortedList.cs
@@ -542,25 +542,15 @@ public void SetValueAtIndex(int index, TValue value)
version++;
}
- public IEnumerator> GetEnumerator()
- {
- return new Enumerator(this, Enumerator.KeyValuePair);
- }
+ public IEnumerator> GetEnumerator() => new Enumerator(this, Enumerator.KeyValuePair);
- IEnumerator> IEnumerable>.GetEnumerator()
- {
- return new Enumerator(this, Enumerator.KeyValuePair);
- }
+ IEnumerator> IEnumerable>.GetEnumerator() =>
+ Count == 0 ? EnumerableHelpers.GetEmptyEnumerator>() :
+ GetEnumerator();
- IDictionaryEnumerator IDictionary.GetEnumerator()
- {
- return new Enumerator(this, Enumerator.DictEntry);
- }
+ IDictionaryEnumerator IDictionary.GetEnumerator() => new Enumerator(this, Enumerator.DictEntry);
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(this, Enumerator.KeyValuePair);
- }
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable>)this).GetEnumerator();
///
/// Gets the key corresponding to the specified index.
@@ -1091,15 +1081,11 @@ public TKey this[int index]
}
}
- public IEnumerator GetEnumerator()
- {
- return new SortedListKeyEnumerator(_dict);
- }
+ public IEnumerator GetEnumerator() =>
+ Count == 0 ? EnumerableHelpers.GetEmptyEnumerator() :
+ new SortedListKeyEnumerator(_dict);
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new SortedListKeyEnumerator(_dict);
- }
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public int IndexOf(TKey key)
{
@@ -1209,15 +1195,11 @@ public TValue this[int index]
}
}
- public IEnumerator GetEnumerator()
- {
- return new SortedListValueEnumerator(_dict);
- }
+ public IEnumerator GetEnumerator() =>
+ Count == 0 ? EnumerableHelpers.GetEmptyEnumerator() :
+ new SortedListValueEnumerator(_dict);
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new SortedListValueEnumerator(_dict);
- }
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public int IndexOf(TValue value)
{
diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs b/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs
index 57f3ed24e596ef..3282996e5bc5d3 100644
--- a/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs
+++ b/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs
@@ -591,7 +591,7 @@ void ICollection.CopyTo(Array array, int index)
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator();
#endregion
diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/Stack.cs b/src/libraries/System.Collections/src/System/Collections/Generic/Stack.cs
index ae5cc7bf0f93a7..2bc209c6a01e0b 100644
--- a/src/libraries/System.Collections/src/System/Collections/Generic/Stack.cs
+++ b/src/libraries/System.Collections/src/System/Collections/Generic/Stack.cs
@@ -152,21 +152,14 @@ void ICollection.CopyTo(Array array, int arrayIndex)
}
// Returns an IEnumerator for this Stack.
- public Enumerator GetEnumerator()
- {
- return new Enumerator(this);
- }
+ public Enumerator GetEnumerator() => new Enumerator(this);
///
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(this);
- }
+ IEnumerator IEnumerable.GetEnumerator() =>
+ Count == 0 ? EnumerableHelpers.GetEmptyEnumerator() :
+ GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(this);
- }
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator();
public void TrimExcess()
{
diff --git a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.Keys.cs b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.Keys.cs
index f4386897680552..a71dad9a34d3c2 100644
--- a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.Keys.cs
+++ b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.Keys.cs
@@ -9,6 +9,8 @@ namespace System.Collections.Tests
{
public class Dictionary_Generic_Tests_Keys : ICollection_Generic_Tests
{
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
protected override bool DefaultValueAllowed => false;
protected override bool DuplicateValuesAllowed => false;
protected override bool IsReadOnly => true;
@@ -61,6 +63,7 @@ public class Dictionary_Generic_Tests_Keys_AsICollection : ICollection_NonGeneri
protected override bool NullAllowed => false;
protected override bool DuplicateValuesAllowed => false;
protected override bool IsReadOnly => true;
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
protected override Type ICollection_NonGeneric_CopyTo_ArrayOfEnumType_ThrowType => typeof(ArgumentException);
protected override bool SupportsSerialization => false;
diff --git a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.Values.cs b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.Values.cs
index 936705f8215b3f..efb7ef3b29ccb0 100644
--- a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.Values.cs
+++ b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.Values.cs
@@ -13,6 +13,9 @@ public class Dictionary_Generic_Tests_Values : ICollection_Generic_Tests
protected override bool DuplicateValuesAllowed => true;
protected override bool IsReadOnly => true;
protected override IEnumerable GetModifyEnumerables(ModifyOperation operations) => new List();
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
protected override ICollection GenericICollectionFactory()
{
@@ -62,10 +65,12 @@ public class Dictionary_Generic_Tests_Values_AsICollection : ICollection_NonGene
protected override bool NullAllowed => true;
protected override bool DuplicateValuesAllowed => true;
protected override bool IsReadOnly => true;
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
protected override Type ICollection_NonGeneric_CopyTo_ArrayOfEnumType_ThrowType => typeof(ArgumentException);
protected override IEnumerable GetModifyEnumerables(ModifyOperation operations) => new List();
protected override bool SupportsSerialization => false;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override Type ICollection_NonGeneric_CopyTo_IndexLargerThanArrayCount_ThrowType => typeof(ArgumentOutOfRangeException);
diff --git a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.cs b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.cs
index b42b1733f0742f..fa12ef55d6c540 100644
--- a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.cs
@@ -14,6 +14,10 @@ namespace System.Collections.Tests
///
public abstract class Dictionary_Generic_Tests : IDictionary_Generic_Tests
{
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
+
protected override ModifyOperation ModifyEnumeratorThrows => ModifyOperation.Add | ModifyOperation.Insert;
protected override ModifyOperation ModifyEnumeratorAllowed => ModifyOperation.Overwrite | ModifyOperation.Remove | ModifyOperation.Clear;
diff --git a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs
index 31271dc03c217d..1a0845a3529865 100644
--- a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs
@@ -12,6 +12,9 @@ namespace System.Collections.Tests
{
public partial class Dictionary_IDictionary_NonGeneric_Tests : IDictionary_NonGeneric_Tests
{
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
+
protected override IDictionary NonGenericIDictionaryFactory()
{
return new Dictionary();
diff --git a/src/libraries/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.AsNonGenericIEnumerable.cs b/src/libraries/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.AsNonGenericIEnumerable.cs
index ff8901ae2afed5..70671721d338af 100644
--- a/src/libraries/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.AsNonGenericIEnumerable.cs
+++ b/src/libraries/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.AsNonGenericIEnumerable.cs
@@ -16,6 +16,7 @@ protected override IEnumerable NonGenericIEnumerableFactory(int count)
return set;
}
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
protected override ModifyOperation ModifyEnumeratorThrows => PlatformDetection.IsNetFramework ? base.ModifyEnumeratorThrows : (base.ModifyEnumeratorAllowed & ~ModifyOperation.Remove);
diff --git a/src/libraries/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.cs b/src/libraries/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.cs
index 65261bfd26e422..c6aee132375a75 100644
--- a/src/libraries/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.cs
@@ -15,6 +15,8 @@ namespace System.Collections.Tests
public abstract class HashSet_Generic_Tests : ISet_Generic_Tests
{
#region ISet Helper Methods
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
protected override bool ResetImplemented => true;
diff --git a/src/libraries/System.Collections/tests/Generic/LinkedList/LinkedList.Generic.Tests.AsNonGenericICollection.cs b/src/libraries/System.Collections/tests/Generic/LinkedList/LinkedList.Generic.Tests.AsNonGenericICollection.cs
index 1b4cf93cabc287..a3854d76ebda12 100644
--- a/src/libraries/System.Collections/tests/Generic/LinkedList/LinkedList.Generic.Tests.AsNonGenericICollection.cs
+++ b/src/libraries/System.Collections/tests/Generic/LinkedList/LinkedList.Generic.Tests.AsNonGenericICollection.cs
@@ -8,6 +8,9 @@ namespace System.Collections.Tests
{
public class LinkedList_ICollection_NonGeneric_Tests : ICollection_NonGeneric_Tests
{
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
+
protected override Type ICollection_NonGeneric_CopyTo_ArrayOfEnumType_ThrowType => typeof(ArgumentException);
protected override void AddToCollection(ICollection collection, int numberOfItemsToAdd)
diff --git a/src/libraries/System.Collections/tests/Generic/LinkedList/LinkedList.Generic.Tests.cs b/src/libraries/System.Collections/tests/Generic/LinkedList/LinkedList.Generic.Tests.cs
index 9d656a84bd98c0..7f0998cac8789e 100644
--- a/src/libraries/System.Collections/tests/Generic/LinkedList/LinkedList.Generic.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/LinkedList/LinkedList.Generic.Tests.cs
@@ -12,6 +12,9 @@ namespace System.Collections.Tests
public abstract partial class LinkedList_Generic_Tests : ICollection_Generic_Tests
{
#region ICollection Helper Methods
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override ICollection GenericICollectionFactory()
{
diff --git a/src/libraries/System.Collections/tests/Generic/List/List.Generic.Tests.cs b/src/libraries/System.Collections/tests/Generic/List/List.Generic.Tests.cs
index 079acc7ade7d42..e10c12c48013c1 100644
--- a/src/libraries/System.Collections/tests/Generic/List/List.Generic.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/List/List.Generic.Tests.cs
@@ -12,6 +12,9 @@ namespace System.Collections.Tests
public abstract partial class List_Generic_Tests : IList_Generic_Tests
{
#region IList Helper Methods
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override IList GenericIListFactory()
{
diff --git a/src/libraries/System.Collections/tests/Generic/Queue/Queue.Generic.Tests.cs b/src/libraries/System.Collections/tests/Generic/Queue/Queue.Generic.Tests.cs
index d38d98655b737c..3fd069023ca253 100644
--- a/src/libraries/System.Collections/tests/Generic/Queue/Queue.Generic.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/Queue/Queue.Generic.Tests.cs
@@ -50,8 +50,9 @@ protected override IEnumerable GenericIEnumerableFactory(int count)
protected override bool Contains(IEnumerable enumerable, T value) => ((Queue)enumerable).Contains(value);
protected override void CopyTo(IEnumerable enumerable, T[] array, int index) => ((Queue)enumerable).CopyTo(array, index);
protected override bool Remove(IEnumerable enumerable) => ((Queue)enumerable).TryDequeue(out _);
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
-
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override Type IGenericSharedAPI_CopyTo_IndexLargerThanArrayCount_ThrowType => typeof(ArgumentOutOfRangeException);
#endregion
diff --git a/src/libraries/System.Collections/tests/Generic/Queue/Queue.Tests.cs b/src/libraries/System.Collections/tests/Generic/Queue/Queue.Tests.cs
index 8f8afc317fcd1d..62b855d3f5dc74 100644
--- a/src/libraries/System.Collections/tests/Generic/Queue/Queue.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/Queue/Queue.Tests.cs
@@ -10,6 +10,8 @@ namespace System.Collections.Tests
public class Queue_ICollection_NonGeneric_Tests : ICollection_NonGeneric_Tests
{
#region ICollection Helper Methods
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override Type ICollection_NonGeneric_CopyTo_ArrayOfEnumType_ThrowType => typeof(ArgumentException);
diff --git a/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.Keys.cs b/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.Keys.cs
index 55d7e446de8706..db626df07701af 100644
--- a/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.Keys.cs
+++ b/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.Keys.cs
@@ -9,6 +9,8 @@ namespace System.Collections.Tests
{
public class SortedDictionary_Generic_Tests_Keys : ICollection_Generic_Tests
{
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
protected override bool DefaultValueAllowed => false;
protected override bool DuplicateValuesAllowed => false;
protected override bool IsReadOnly => true;
@@ -59,6 +61,7 @@ public class SortedDictionary_Generic_Tests_Keys_AsICollection : ICollection_Non
protected override bool NullAllowed => false;
protected override bool DuplicateValuesAllowed => false;
protected override bool IsReadOnly => true;
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
protected override IEnumerable GetModifyEnumerables(ModifyOperation operations) => new List();
protected override ICollection NonGenericICollectionFactory()
diff --git a/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.Values.cs b/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.Values.cs
index 3030fdaaa08205..fd4669f7707dd4 100644
--- a/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.Values.cs
+++ b/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.Values.cs
@@ -9,6 +9,8 @@ namespace System.Collections.Tests
{
public class SortedDictionary_Generic_Tests_Values : ICollection_Generic_Tests
{
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
protected override bool DefaultValueAllowed => true;
protected override bool DuplicateValuesAllowed => true;
protected override bool IsReadOnly => true;
@@ -61,6 +63,7 @@ public class SortedDictionary_Generic_Tests_Values_AsICollection : ICollection_N
protected override bool NullAllowed => true;
protected override bool DuplicateValuesAllowed => true;
protected override bool IsReadOnly => true;
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
protected override IEnumerable GetModifyEnumerables(ModifyOperation operations) => new List();
protected override bool SupportsSerialization => false;
diff --git a/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.cs b/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.cs
index cac00bc6723b4d..830181188c5fa3 100644
--- a/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Generic.Tests.cs
@@ -13,7 +13,9 @@ namespace System.Collections.Tests
public abstract class SortedDictionary_Generic_Tests : IDictionary_Generic_Tests
{
#region IDictionary Helper Methods
-
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override bool DefaultValueWhenNotAllowed_Throws { get { return false; } }
protected override IDictionary GenericIDictionaryFactory()
diff --git a/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Tests.cs b/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Tests.cs
index f83ed756cc7f19..7b393933029491 100644
--- a/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/SortedDictionary/SortedDictionary.Tests.cs
@@ -9,6 +9,8 @@ namespace System.Collections.Tests
public class SortedDictionary_IDictionary_NonGeneric_Tests : IDictionary_NonGeneric_Tests
{
#region IDictionary Helper Methods
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override IDictionary NonGenericIDictionaryFactory()
{
diff --git a/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.Keys.cs b/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.Keys.cs
index 58e69384033d0d..4c5971cd359159 100644
--- a/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.Keys.cs
+++ b/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.Keys.cs
@@ -9,6 +9,9 @@ namespace System.Collections.Tests
{
public class SortedList_Generic_Tests_Keys : IList_Generic_Tests
{
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override bool DefaultValueAllowed => false;
protected override bool DuplicateValuesAllowed => false;
protected override bool IsReadOnly => true;
@@ -57,6 +60,7 @@ public class SortedList_Generic_Tests_Keys_AsICollection : ICollection_NonGeneri
protected override bool NullAllowed => false;
protected override bool DuplicateValuesAllowed => false;
protected override bool IsReadOnly => true;
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
protected override bool SupportsSerialization => false;
diff --git a/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.Values.cs b/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.Values.cs
index 14eeaa0166b208..32ec7e651f3cbb 100644
--- a/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.Values.cs
+++ b/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.Values.cs
@@ -9,6 +9,9 @@ namespace System.Collections.Tests
{
public class SortedList_Generic_Tests_Values : IList_Generic_Tests
{
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override bool DefaultValueAllowed => true;
protected override bool DuplicateValuesAllowed => true;
protected override bool IsReadOnly => true;
@@ -57,6 +60,7 @@ public class SortedList_Generic_Tests_Values_AsICollection : ICollection_NonGene
protected override bool NullAllowed => true;
protected override bool DuplicateValuesAllowed => true;
protected override bool IsReadOnly => true;
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
protected override bool SupportsSerialization => false;
diff --git a/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.cs b/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.cs
index 7fc503b3b96c97..2a7966dab14e9e 100644
--- a/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Generic.Tests.cs
@@ -13,6 +13,9 @@ namespace System.Collections.Tests
public abstract class SortedList_Generic_Tests : IDictionary_Generic_Tests
{
#region IDictionary Helper Methods
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_Current_UndefinedOperation_Throws => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override IDictionary GenericIDictionaryFactory()
{
diff --git a/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Tests.cs b/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Tests.cs
index 85bec3a725bacc..d0c7435ff5bf6a 100644
--- a/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/SortedList/SortedList.Tests.cs
@@ -9,7 +9,8 @@ namespace System.Collections.Tests
public class SortedList_IDictionary_NonGeneric_Tests : IDictionary_NonGeneric_Tests
{
#region IDictionary Helper Methods
-
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override IDictionary NonGenericIDictionaryFactory()
{
return new SortedList();
diff --git a/src/libraries/System.Collections/tests/Generic/Stack/Stack.Generic.Tests.cs b/src/libraries/System.Collections/tests/Generic/Stack/Stack.Generic.Tests.cs
index 1edc037d7cd210..4c5c5a49d243e1 100644
--- a/src/libraries/System.Collections/tests/Generic/Stack/Stack.Generic.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/Stack/Stack.Generic.Tests.cs
@@ -32,6 +32,9 @@ protected Stack GenericStackFactory(int count)
protected override Type IGenericSharedAPI_CopyTo_IndexLargerThanArrayCount_ThrowType => typeof(ArgumentOutOfRangeException);
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
+
#endregion
protected override IEnumerable GenericIEnumerableFactory()
diff --git a/src/libraries/System.Collections/tests/Generic/Stack/Stack.Tests.cs b/src/libraries/System.Collections/tests/Generic/Stack/Stack.Tests.cs
index 76a6e74e4f69bd..05a4cb340eae6d 100644
--- a/src/libraries/System.Collections/tests/Generic/Stack/Stack.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/Stack/Stack.Tests.cs
@@ -23,7 +23,9 @@ protected override ICollection NonGenericICollectionFactory()
return new Stack();
}
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
+ protected override bool Enumerator_Empty_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override Type ICollection_NonGeneric_CopyTo_IndexLargerThanArrayCount_ThrowType => typeof(ArgumentOutOfRangeException);
diff --git a/src/libraries/System.Private.CoreLib/src/System/ArraySegment.cs b/src/libraries/System.Private.CoreLib/src/System/ArraySegment.cs
index a5431a9209295c..45fe8fdee166aa 100644
--- a/src/libraries/System.Private.CoreLib/src/System/ArraySegment.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/ArraySegment.cs
@@ -261,12 +261,18 @@ bool ICollection.Remove(T item)
#region IEnumerable
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ ThrowInvalidOperationIfDefault();
+ return
+ Count == 0 ? SZGenericArrayEnumerator.Empty :
+ new Enumerator(this);
+ }
#endregion
#region IEnumerable
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator();
#endregion
private void ThrowInvalidOperationIfDefault()
diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs
index 3b840d04efafd7..f959827b1da605 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs
@@ -339,7 +339,8 @@ private void CopyTo(KeyValuePair[] array, int index)
public Enumerator GetEnumerator() => new Enumerator(this, Enumerator.KeyValuePair);
IEnumerator> IEnumerable>.GetEnumerator() =>
- new Enumerator(this, Enumerator.KeyValuePair);
+ Count == 0 ? SZGenericArrayEnumerator>.Empty :
+ GetEnumerator();
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
@@ -1100,7 +1101,7 @@ void ICollection.CopyTo(Array array, int index)
}
}
- IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this, Enumerator.KeyValuePair);
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable>)this).GetEnumerator();
///
/// Ensures that the dictionary can hold up to 'capacity' entries without any further expansion of its backing storage
@@ -1513,9 +1514,11 @@ bool ICollection.Remove(TKey item)
return false;
}
- IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary);
+ IEnumerator IEnumerable.GetEnumerator() =>
+ Count == 0 ? SZGenericArrayEnumerator.Empty :
+ GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary);
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator();
void ICollection.CopyTo(Array array, int index)
{
@@ -1705,9 +1708,11 @@ void ICollection.Clear() =>
bool ICollection.Contains(TValue item) => _dictionary.ContainsValue(item);
- IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary);
+ IEnumerator IEnumerable.GetEnumerator() =>
+ Count == 0 ? SZGenericArrayEnumerator.Empty :
+ GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary);
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator();
void ICollection.CopyTo(Array array, int index)
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs
index fe7912af6a710e..7537e2d4b80f90 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs
@@ -358,9 +358,11 @@ public bool Remove(T item)
public Enumerator GetEnumerator() => new Enumerator(this);
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator() =>
+ Count == 0 ? SZGenericArrayEnumerator.Empty :
+ GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator();
#endregion
diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs
index 1cfe6a699b2421..b3c165595b7654 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs
@@ -625,14 +625,13 @@ public void ForEach(Action action)
// while an enumeration is in progress, the MoveNext and
// GetObject methods of the enumerator will throw an exception.
//
- public Enumerator GetEnumerator()
- => new Enumerator(this);
+ public Enumerator GetEnumerator() => new Enumerator(this);
- IEnumerator IEnumerable.GetEnumerator()
- => new Enumerator(this);
+ IEnumerator IEnumerable.GetEnumerator() =>
+ Count == 0 ? SZGenericArrayEnumerator.Empty :
+ GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator()
- => new Enumerator(this);
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator();
public List GetRange(int index, int count)
{
@@ -1145,6 +1144,8 @@ public bool TrueForAll(Predicate match)
public struct Enumerator : IEnumerator, IEnumerator
{
+ internal static IEnumerator? s_emptyEnumerator;
+
private readonly List _list;
private int _index;
private readonly int _version;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Queue.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Queue.cs
index 98a2f202556a35..ba27a5ed9d397c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Queue.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Queue.cs
@@ -183,21 +183,14 @@ public void Enqueue(T item)
// GetEnumerator returns an IEnumerator over this Queue. This
// Enumerator will support removing.
- public Enumerator GetEnumerator()
- {
- return new Enumerator(this);
- }
+ public Enumerator GetEnumerator() => new Enumerator(this);
///
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(this);
- }
+ IEnumerator IEnumerable.GetEnumerator() =>
+ Count == 0 ? SZGenericArrayEnumerator.Empty :
+ GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(this);
- }
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator();
// Removes the object at the head of the queue and returns it. If the queue
// is empty, this method throws an
diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/ObjectModel/ReadOnlyCollection.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/ObjectModel/ReadOnlyCollection.cs
index 57be3812a5142c..874db5fad5f47e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Collections/ObjectModel/ReadOnlyCollection.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Collections/ObjectModel/ReadOnlyCollection.cs
@@ -43,9 +43,8 @@ public void CopyTo(T[] array, int index)
}
public IEnumerator GetEnumerator() =>
- list.Count == 0 ?
- SZGenericArrayEnumerator.Empty :
- list.GetEnumerator();
+ list.Count == 0 ? SZGenericArrayEnumerator.Empty :
+ list.GetEnumerator();
public int IndexOf(T value)
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs
index 0c9806eadf4cf7..7a8f8da784c088 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs
@@ -258,7 +258,7 @@ IEnumerator> IEnumerable>.
{
Container c = _container;
return c is null || c.FirstFreeEntry == 0 ?
- ((IEnumerable>)Array.Empty>()).GetEnumerator() :
+ SZGenericArrayEnumerator>.Empty :
new Enumerator(this);
}
}
diff --git a/src/libraries/System.Runtime/tests/System/ArraySegmentTests.cs b/src/libraries/System.Runtime/tests/System/ArraySegmentTests.cs
index bbe9a8646e2fc3..171b9bf5d24eb5 100644
--- a/src/libraries/System.Runtime/tests/System/ArraySegmentTests.cs
+++ b/src/libraries/System.Runtime/tests/System/ArraySegmentTests.cs
@@ -24,6 +24,7 @@ protected override IList GenericIListFactory(int count)
return Factory(count * 2, count / 2, count);
}
+ protected override bool Enumerator_Empty_UsesSingletonInstance => true;
protected override bool Enumerator_Current_UndefinedOperation_Throws => true;
protected override bool Enumerator_ModifiedDuringEnumeration_ThrowsInvalidOperationException => false;
protected override bool IsReadOnly_ValidityValue => true;