Implementing IEnumerable

Hot off the presses... What do you think?

 ..brad

Implementing IEnumerable

Almost all collections expose some
way to enumerate elements it contains. The IEnumerable interface
encapsulates this notion such that common facilities can be built that work on
any kind of collection. These guidelines

apply to any type implementing
ICollection, IList or IDictionary as well.
 

?    
Do see the
generics guidelines in section x.y
(tbd)

?    
Do see section 11 for more collections
guidelines

?    
Do implement IEnumerable on any type
that can be enumerated

?     
Do name the class
ItemTypeCollection for implementations that contain homogenous types.
Such as StringCollection, EmployeeCollection, etc

?    
Do
explicitly implement
IEnumerable.GetEnumerator()

?    
Do
provide a GetEnumerator() method
that returns a nested public struct called “Enumerator”

Rationale: the foreach language
construct will prefer calling the method named GetEnumerator (that follows the
enumerator pattern) rather than the interface method which means there will be
one less GC heap allocation each time the collection is enumerated.  

?    
Do explicitly implement the
IEnumertor.Current property on the Enumerator struct

?    
Do provide a strongly typed Current
property that returns the item type
on the Enumerator
struct

Rationale: If item type is a value
type this avoids a boxing operation each time through the loop. If item
type is a reference type there is a small savings for not having to do the
cast.

?    
Avoid having members on your
collection be virtual unless extensibility is truly
required

Rationale: The
JIT is not
able to inline calls to virtual methods.  

These guidelines lead to this
pattern…

public
class
ItemTypeCollection: IEnumerable

{

public
struct
Enumerator : IEnumerator

{

public
ItemType Current { get {… }
}

object
IEnumerator.Current { get {
return
Current; } }

public
bool
MoveNext() { … }

}

public
Enumerator GetEnumerator() { … }

IEnumerator
IEnumerable.GetEnumerator() { … }

}

Tradeoff: Implementing this
pattern involves having an extra public type (the Enumerator) and several extra
public methods that are really there just for infrastructure reasons. These types add to the perceived
complexity of the
API and must be
documented, tested, versioned, etc. As such this pattern should only be followed where performance is
paramount.

?    
Prefer implementing IEnumerable
interface with optimistic concurrency

Rationale:  There are two legitimate ways to
implement the IEnumerable interface. 
The first is to assume that the collection will not be modified while it
is being enumerated.  If it is
modified throw an InvalidOperationException exception.  The 2nd way is to make a snap-shot of
the collection in the enumerator thus isolating the enumerator from changes in
the underlying collection.  For most
usages for enumerable.  For most
general usage scenarios the optimistic 
concurrency model provides net better performance.