Search Forum
(57415 Postings)
Search Site/Articles

Archived Articles
712 Articles

C# Books
C# Consultants
What Is C#?
Download Compiler
Code Archive
Archived Articles
Advertise
Contribute
C# Jobs
Beginners Tutorial
C# Contractors
C# Consulting
Links
C# Manual
Contact Us
Legal

GoDiagram for .NET from Northwoods Software www.nwoods.com


              
Printable Version

Building Your Own Enumerator To Use With The foreach Construct
By Richard Hernandez

We are going to use "foreach" to iterate through our collection of fruit objects.

Lets assume that we have a class called Fruit which contains the fields; string name ,int num and bool ripe. We build a class called Fruits which represents a collection of fruit objects.

public class Fruits
{
 //we don’t have to specify private as this is the default modifier
 //it’s just included to highlight the fact that this is private to
 //the Fruits collection. 

 private Fruit[] fruitArray; 

 //Create a basket of fruit    

 public Fruits()
 {
  fruitArray = new Fruit[3];
  fruitArray[0] = new Fruit("Banana",false,3);
  fruitArray[1] = new Fruit("Apples",true,5);
  fruitArray[2] = new Fruit("Oranges",true,3);
 }
}
In order to obtain each Fruit from the Fruits collection it would be convenient if the object user could iterate over the Fruits type using the foreach construct. It would be reasonable to code:
public class FruitBar
{
 public static void Main()
 {
  Fruits fruitbasket = new Fruits();
  //Show only the ripe fruit
  foreach (Fruit f in fruitbasket)
  {
   if (f.ripe == true)
   {
    Console.WriteLine("Name : {0}",f.name);
    Console.WriteLine("Amount : {0}",f.num);  
   }
   {  
   }
} 
Unfortunately attempting to execute this code results in the compiler complaining that it cannot find GetEnumerator.

To use the foreach syntax your class must support the IEnumerable interface found in the System.Collections namespace. IEnumerable defines only one method, public IEnumerator GetEnumerator(), notice that this method returns another interface IEnumerator also found in System.Collections namespace.

IEnumerator supports a simple iteration over a collection. It publishes two methods and a property:

bool MoveNext():
Advances the enumerator to the next element in the collection. Returns true if successfully advanced to the next element in the collection and false if the move would take it beyond the last element.

void Reset():
Sets the enumerator to the initial position, which is before the first element in the collection (-1)

object Current {get;}:
Gets the current element in the collection. Throws Exception Type InvalidOperationException.

To successfully implement an enumerator we must keep in mind the following protocol. After an enumerator is created or after a Reset, MoveNext must be called to advance the enumerator to the first element of the collection before reading the value of Current. Current throws an exception if the last call to MoveNext returns false. Current does not move the position of the enumerator.

This is by no means a thorough discussion on implementing enumeration, more an introduction to using enumerators with foreach.

Here is an example of the changes required to implement an enumerator for use with the foreach construct.

namespace MyFruitBasket
{
 public class Fruit
 {
  //this is a bad way to declare fields in a class
  //but this is just an example 
  public string name;
  public bool ripe;
  public int num;

  public Fruit(string nme, bool rp, int n)
  {
   name = nme;
   ripe = rp;
   num = n;
  }
 }
The Fruits collection implements the IEnumerable and IEnumerator interfaces.
public class Fruits :IEnumerable,IEnumerator
{
 Fruit[] fruitArray;
 //current position in array set to initial position
 int position = -1;
 //Create a basket of fruit    
 public Fruits()
 {
  fruitArray = new Fruit[3];
  fruitArray[0] = new Fruit("Banana",false,3);
  fruitArray[1] = new Fruit("Apples",true,5);
  fruitArray[2] = new Fruit("Oranges",true,3);
 }

 //Implement IEnumerable

 public IEnumerator GetEnumerator()
 {
  return (IEnumerator)this;
 }

 //Implement IEnumerator
 public bool MoveNext()
 {
  position++;
  if (position < fruitArray.Length)
  {
   return true;
  }
  else
  {
   return false;
  }
 }
 public void Reset()
 {
  position = -1;
 }
 public object Current
 {
  get{return fruitArray[position];}
 }
}

class FruitBar
{
 static void Main(string[] args)
 {
  Fruits fruitbasket = new Fruits();
  //Present only the ripe fruit
  foreach (Fruit f in fruitbasket)
  {           
   if (f.ripe == true)
   Console.WriteLine("Name : {0}",f.name);
   Console.WriteLine("Amount : {0}",f.num);  
  }     
  string x = Console.ReadLine();
  }
 }
}
I hope this has been of some help.