views:

554

answers:

6

I noticed that List<T> defines its enumerator as a struct, while ArrayList defines its enumerator as a class. What's the difference? If I am to write an enumerator for my class, which one would be preferable?

EDIT: My requirements cannot be fulfilled using yield, so I'm implementing an enumerator of my own. That said, I wonder whether it would be better to follow the lines of List<T> and implement it as a struct.

+4  A: 

Write it using yield return.

As to why you might otherwise choose between class or struct, if you make it a struct then it gets boxed as soon as it is returned as an interface, so making it a struct just causes additional copying to take place. Can't see the point of that!

Daniel Earwicker
Which mandates the question: why does List<T> use a struct enumerator?
Hosam Aly
Until someone comes up with a reason why it's advantageous, we'll have to assume the Microserf responsible for it went temporarily insane.
Daniel Earwicker
+3  A: 

An enumerator is inherently a changing structure, since it needs to update internal state to move on to the next value in the original collection.

In my opinion, structs should be immutable, so I would use a class.

Lasse V. Karlsen
+6  A: 

The easiest way to write an enumerator in C# is with the "yield return" pattern. For example.

public IEnumerator<int> Example() {
  yield return 1;
  yield return 2;
}

This pattern will generate all of the enumerator code under the hood. This takes the decision out of your hands.

JaredPar
+2  A: 

Like this others, I would choose a class. Mutable structs are nasty. (And as Jared suggests, I'd use an iterator block. Hand-coding an enumerator is fiddly to get right.)

See this thread for an example of the list enumerator being a mutable struct causing problems...

Jon Skeet
Well, that example proved I should make it a class. :)But why is List implemented that way? Why was it not corrected?
Hosam Aly
It's certainly too late to change it now - but I don't know why it was designed that way in the first place. Presumably in the name of efficiency - but a bad call, IMO.
Jon Skeet
I presumed it was so the current state of an enumerator could be 'saved' just by copying the enumerator to another variable - I've recently used this 'feature' myself to do linked list slices (as LinkedList<T>.Enumerator is also a struct)
thecoop
+1  A: 

To expand on @Earwicker: you're usually better off not writing an enumerator type, and instead using yield return to have the compiler write it for you. This is because there are a number of important subtleties that you might miss if you do it yourself.

See SO question "What is the yield keyword used for in C#?" for some more details on how to use it.

Also Raymond Chen has a series of blog posts that show you how to implement an iterator properly without yield return, which shows just how complex it is, and why you should just use yield return.

Jay Bazuzi
A: 

There's a couple of blog posts that cover exactly this issue. Basically, enumerator structs are a really really bad idea...

thecoop