Question about IEnumerable and Interface Signatures

J

jmDesktop

In the code below from MSDN

How do the PeopleEnum methods ever get called?

foreach (Person p in peopleList)
Console.WriteLine(p.firstName + " " + p.lastName);

What is going on behind the scenes in the foreach?

Also, I could not find where the interface signatures were for the
IEnumerable and IEnumerator. How did they know what methods they were
required to use from the interface signature. I looked them up on
MSDN, but didn't see any references to GetEnumerator or MoveNext.
Just this type explanation:

[ComVisibleAttribute(true)]
[GuidAttribute("496B0ABF-CDEE-11d3-88E8-00902754C43A")]
public interface IEnumerator

http://msdn.microsoft.com/en-us/library/system.collections.ienumerable(VS.80).aspx

Thanks.

---
using System;
using System.Collections;

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 = pArray;
}
}

public IEnumerator 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;
}

public object Current
{
get
{
try
{
return _people[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
}

class App
{
static void Main()
{
Person[] peopleArray = new Person[3]
{
new Person("John", "Smith"),
new Person("Jim", "Johnson"),
new Person("Sue", "Rabon"),
};

People peopleList = new People(peopleArray);
foreach (Person p in peopleList)
Console.WriteLine(p.firstName + " " + p.lastName);

}
}

/* This code produces output similar to the following:
*
* John Smith
* Jim Johnson
* Sue Rabon
*
*/
 
J

Jon Skeet [C# MVP]

In the code below from MSDN

How do the PeopleEnum methods ever get called?

foreach (Person p in peopleList)
Console.WriteLine(p.firstName + " " + p.lastName);

What is going on behind the scenes in the foreach?

foreach calls GetEnumerator() on the IEnumerable to get an
IEnumerator, then calls MoveNext() and Current on the IEnumerator,
executing the body of the loop each time, until MoveNext() returns
false or the body of the foreach loop exits early somehow (break/
return/exception).

It then (irrespective of whether it reached the end or not) checks
whether or not the IEnumerator implements IDisposable, and calls
Dispose if so. (The generic IEnumerator<T> interface extends
IDisposable, so if there's a generic IEnumerable<T> the compiler
doesn't need to perform an execution-time check here - it just calls
Dispose.)
Also, I could not find where the interface signatures were for the
IEnumerable and IEnumerator. How did they know what methods they were
required to use from the interface signature. I looked them up on
MSDN, but didn't see any references to GetEnumerator or MoveNext.

The interfaces IEnumerable and IEnumerator are both defined in the
System.Collections namespace, and the methods within them are
documented in MSDN in the normal way. The generic forms are in the
System.Collections.Generic namespace.

In fact, the C# compiler can use foreach without implementing
IEnumerable and IEnumerator at all - but it's extremely rare.

Jon
 
S

Sujeet

Rather that explaining here what happens, I would suggest you compile the
code and open the assembly in ildasm.exe to exactly see what the compiler
does behind the scenes. Thats the best way IMO to know.

Sujeet
 
S

Sujeet

Adding to what John said, specifically for foreach statement the 'peopleList'
type does not have to implement IEnumearble. It can also just have a method
GetEnumerator() that returns a type Person that has a public instance
'MoveNext()' method that returns a bool and a public instance property
'Current' that returns the type 'Person'

But IMO implementing IEnumerable explicitly is more cleaner and easy to read.

Sujeet
 
J

Jon Skeet [C# MVP]

Sujeet said:
Adding to what John said, specifically for foreach statement the 'peopleList'
type does not have to implement IEnumearble. It can also just have a method
GetEnumerator() that returns a type Person that has a public instance
'MoveNext()' method that returns a bool and a public instance property
'Current' that returns the type 'Person'

But IMO implementing IEnumerable explicitly is more cleaner and easy to read.

Agreed - although I'd implement IEnumerable<Person> and do it with an
iterator block :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top