Why in this example (derived from msdn), in the GetEnumerator method, does the new PeopleEnum return an IEnumerator?
Why does this example from MSDN, in the method GetEnumerator
, PeopleEnum
return IEnumerator
?
public class Person
{
public Person(string fName, string lName)
{
this.firstName = fName;
this.lastName = lName;
}
public string firstName;
public string lastName;
}
public class People : IEnumerable
{
private Person[] _people;
public People(Person[] pArray)
{
_people = new Person[pArray.Length];
for (int i = 0; i < pArray.Length; i++)
{
_people[i] = pArray[i];
}
}
//why???
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator) GetEnumerator();
}
public PeopleEnum GetEnumerator()
{
return new PeopleEnum(_people);
}
}
public class PeopleEnum : IEnumerator
{
public Person[] _people;
// Enumerators are positioned before the first element
// until the first MoveNext() call.
int position = -1;
public PeopleEnum(Person[] list)
{
_people = list;
}
public bool MoveNext()
{
position++;
return (position < _people.Length);
}
public void Reset()
{
position = -1;
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public Person Current
{
get
{
try
{
return _people[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
UPDATE: BTW, if the Array datatype implements the ICloneable interface, why did msdn copy the pArray to _people by writing a for loop?
a source to share
For the correct implementation of the interface, IEnumerable
you must specify exactly IEnumerator
. It does this using an "explicit interface implementation", so you see in the public API PeopleEnum
, but IEnumerable
is still happy
But in reality, you would very rarely write an enumerator this way in C # 2.0 or higher; you have to use an iterator ( yield return
) block . See C # in depth , chapter 6 (free chapter!).
For information, the reason it PeopleEnum
exists at all here is because it looks like the .NET 1.1 sample, where this is the only way to create a typed enumerator. In .NET 2.0 and up, there is a IEnumerable<T>
/ IEnumerator<T>
which is typed (via generics) .Current
.
In .NET 2.0 / C # 2.0 (or higher) I would just:
public class People : IEnumerable<Person> {
/* snip */
public IEnumerator<Person> GetEnumerator() {
return ((IEnumerable<Person>)_people).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() { return _people.GetEnumerator();}
}
a source to share
Types that implement IEnumerable require the GetEnumerator method, which returns IEnumerator. In this example (which is quite outdated as in C # 2.0) there is an enumerator class PeopleEnum that implements IEnumerator. This is what is used internally by the C # foreach statement.
A more modern example would look like this. Note that there is now no need for the PeopleEnum class when C # supports iterators. Effectively the compiler does all the heavy lifting for you.
public class People : IEnumerable
{
private Person[] _people;
public People(Person[] pArray)
{
_people = new Person[pArray.Length];
for (int i = 0; i < pArray.Length; i++)
{
_people[i] = pArray[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
for (int i=0; i < _people.Length; i++) {
yield return _people[i];
}
}
}
a source to share