From what I’ve read, a design decision was made for certain Collections’s Enumerator Types to be mutable structs instead of reference types for performance reasons. List.Enumerator is the most well known.
I was investigating some old code that used arrays, and was surprised to discover that C# Arrays return the type SZGenericArrayEnumerator as their generic enumerator type, which is a reference type.
I am wondering if anyone knows why Array’s generic iterator was implemented as a reference type when so many other performance critical collections used mutable structs instead.
Good question.
First off, you are correct. Though in general, mutable value types are a bad code smell, in this case they are justified:
Because if you’re the sort of person who is concerned about the performance of enumerating an array then why are you using an enumerator in the first place? It’s an array for heaven’s sake; just write a
forloop that iterates over its indicies like a normal person and never allocate the enumerator. (Or aforeachloop; the C# compiler will rewrite theforeachloop into the equivalentforloop if it knows that the loop collection is an array.)The only reason why you’d obtain an enumerator from an array in the first place is if you are passing it to a method that takes an
IEnumerator<T>, in which case if the enumerator is a struct then you’re going to be boxing it anyway. Why take on the expense of making the value type and then boxing it? Just make it a reference type to begin with.