: C# 2008 Programmer

Implementing IEnumerable and IEnumerator

Implementing IEnumerable<T> and IEnumerator<T>

Besides using the iterators feature in your class to allow clients to step through its internal elements with foreach, you can make your class support the foreach statement by implementing the IEnumerable and IEnumerator interfaces. The generic equivalents of these two interfaces are IEnumerable<T> and IEnumerator<T>, respectively.

Use the generic versions because they are type safe.

In .NET, all classes that enumerate objects must implement the IEnumerable (or the generic IEnumerable<T>) interface. The objects enumerated must implement the IEnumerator (or the generic IEnumerable<T>) interface, which has the following members:

?Current Returns the current element in the collection

?MoveNext() Advances to the next element in the collection

?Reset() Resets the enumerator to its initial position

The IEnumerable interface has one member:

?GetEnumerator() Returns the enumerator that iterates through a collection

All the discussions from this point onward use the generic versions of the IEnumerable and IEnumerator interfaces because they are type-safe.

To understand how the IEnumerable<T> and IEnumerator<T> interfaces work, modify SpamPhraseList class to implement the IEnumerable<T> interface:

public class SpamPhraseList : IEnumerable<string> {
protected string[] Phrases = new string[]{
"pain relief", "paxil", "pharmacy", "phendimetrazine",
"phentamine", "phentermine", "pheramones", "pherimones",
"photos of singles", "platinum-celebs", "poker-chip",
"poze", "prescription", "privacy assured", "product for less",
"products for less", "protect yourself", "psychic"
};
//---for generic version of the class---
public IEnumerator<string> GetEnumerator() {}
//---for non-generic version of the class---
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {}
}

Notice that for the generic version of the IEnumerable interface, you need to implement two versions of the GetEnumerator() methods one for the generic version of the class and one for the nongeneric version.

To ensure that the SpamPhraseList class can enumerate the strings contained within it, you define an enumerator class within the SpamPhraseList class:

public class SpamPhraseList : IEnumerable<string> {
private class SpamPhrastListEnum : IEnumerator<string> {
private int index = -1;
private SpamPhraseList spamlist;
public SpamPhrastListEnum(SpamPhraseList sl) {
this.spamlist = sl;
}
//---for generic version of the class---
string IEnumerator<string>.Current {
get {
return spamlist.Phrases[index];
}
}
//---for non-generic version of the class---
object System.Collections.IEnumerator.Current {
get {
return spamlist.Phrases[index];
}
}
bool System.Collections.IEnumerator.MoveNext() {
index++;
return index < spamlist.Phrases.Length;
}
void System.Collections.IEnumerator.Reset() {
index = -1;
}
void IDisposable.Dispose() { }
}
protected string[] Phrases = new string[] {
"pain relief", "paxil", "pharmacy", "phendimetrazine",
"phentamine", "phentermine", "pheramones", "pherimones",
"photos of singles", "platinum-celebs", "poker-chip", "poze",
"prescription", "privacy assured", "product for less",
"products for less", "protect yourself", "psychic"
};
public IEnumerator<string> GetEnumerator() {
return new SpamPhrastListEnum(this);
}
//---for non-generic version of the class---
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return new SpamPhrastListEnum(this);
}
}

In this example, the SpamPhrastListEnum class implements the IEnumerator<string> interface and provides the implementation for the Current property and the MoveNext() and Reset() methods.

To print out all the elements contained within a SpamPhraseList object, you can use the same statements that you used in the previous section:

SpamPhraseList list = new SpamPhraseList();
foreach (string s in list) //---error---
Console.WriteLine(s);

Behind the scenes, the compiler is generating the following code for the foreach statement:

SpamPhraseList list = new SpamPhraseList();
IEnumerator<string> s = list.GetEnumerator();
while (s.MoveNext())
Console.WriteLine((string)s.Current);


: 1.038. /Cache: 3 / 1