This is part 10/17 of my Exploring the .NET CoreFX series.
The .NET Core’s
System.Collections.Immutable.ImmutableArray provides two enumerators. The first has been highly tuned for speed, and the second is a fallback for compatibility when it is required.
The high-performance enumerator uses the following performance optimizations:
- The enumerator is a
struct, rather than a
class, so that it is stack-allocated rather than heap-allocated.
- The enumerator does not implement
IEnumerator, as this would require it to implement
IDisposable. By not implementing
IDisposablethe iterator will inline during
- The enumerator does not use range checks in
Enumerator.Current; it requires on .NET’s array range checks to throw an exception instead.
The high-performance enumerator is called
ImmutableArray.Enumerator, which is returned by
Note that this method is not defined by any interface
ImmutableArray implements, but it will be used by
foreach. This is because
foreach is pattern-based rather than interface-based. What this means is that
foreach does not require an object to implement
IEnumerable as long as it implements a method named
GetEnumerator(). Similarly, the returned object is not required to implement
IEnumerator as long as it implements a
Current property and a
The result of all this work is that
foreach over an
ImmutableArray is just as efficient as a hand-written
- To improve the performance of foreach, consider writing a specialized, struct-based enumerator in addition to the traditional one.