New Features in C# 2.0—GetEnumerator: How do I do that?

Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio


Jump to: navigation, search
CSharp-Online.NET:Tutorials
C# Tutorials

New Features in C# 2.0

© 2005 O'Reilly Media, Inc.

How do I do that?

As noted in the previous lab, the IEnumerable interface requires that you implement only one method, GetEnumerator, as shown in Example 1-5.

Example 1-5. Enumerating through your linked list

using System;
using System.Collections.Generic;
 
namespace GenericEnumeration
{
  public class Pilgrim : IComparable<Pilgrim>
  {
    private string name;
    public Pilgrim(string name)
    {
      this.name = name;
    }
    public override string ToString( )
    {
      return this.name;
    }
 
    // implement the interface
    public int CompareTo(Pilgrim rhs)
    {
      return this.name.CompareTo(rhs.name);
    }
    public bool Equals(Pilgrim rhs)
    {
      return this.name = = rhs.name;
    }
  }
 
  // node must implement IComparable of Node of T
  // node now implements IEnumerable allowing its use 
  // in a foreach loop
  public class Node<T> : IComparable<Node<T>>, 
    IEnumerable<Node<T>>  where T: IComparable<T>
  {
    // member fields
    private T data;
    private Node<T> next = null;
    private Node<T> prev = null;
 
    // constructor
    public Node(T data)
    {
      this.data = data;
    }
 
    // properties
    public T Data { get { return this.data; } }
    public Node<T> Next
    {
      get { return this.next; }
    }
    public int CompareTo(Node<T> rhs)
    {
      return data.CompareTo(rhs.data);
    }
    public bool Equals(Node<T> rhs)
    {
      return this.data.Equals(rhs.data);
    }
 
    // methods
    public Node<T> Add(Node<T> newNode)
    {
      if (this.CompareTo(newNode) > 0) // goes before me
      {
        newNode.next = this; // new node points to me
        // if I have a previous, set it to point to
        // the new node as its next
        if (this.prev != null)
        {
          this.prev.next = newNode;
          newNode.prev = this.prev;
        }
 
        // set prev in current node to point to new node
        this.prev = newNode;
        // return the newNode in case it is the new head
        return newNode;
      }
      else // goes after me
      {
        // if I have a next, pass the new node along for comparison
        if (this.next != null)
        {
          this.next.Add(newNode);
        }
 
        // I don't have a next so set the new node
        // to be my next and set its prev to point to me.
        else
        {
          this.next = newNode;
          newNode.prev = this;
        }
        return this;
      }
    }
 
    public override string ToString( )
    {
      string output = data.ToString( );
      if (next != null)
      {
        output += ", " + next.ToString( );
      }
      return output;
    }
 
    // Method required by IEnumerable
    IEnumerator<Node<T>> IEnumerable<Node<T>>.GetEnumerator( )
    {
      Node<T> nextNode = this;
      // iterate through all the nodes in the list
      // yielding each in turn
      do
      {
        Node<T> returnNode = nextNode;
        nextNode = nextNode.next;
        yield return returnNode;
      } while (nextNode != null);
    }
 
    System.Collections.IEnumerator 
      System.Collections.IEnumerable.GetEnumerator()
    {
      throw new NotImplementedException();
    }
  } // end class
 
  // implements IEnumerable so that you can use a LinkedList
  // in a foreach loop
  public class LinkedList<T> : IEnumerable<T> 
    where T : IComparable<T>
  {
    // member fields
    private Node<T> headNode = null;
    // properties
    // indexer
    public T this[int index]
    {
      get
      {
        int ctr = 0;
        Node<T> node = headNode;
        while (node != null && ctr <= index)
        {
          if (ctr = = index)
          {
            return node.Data;
          }
          else
          {
            node = node.Next;
        }
        ++ctr;
        } // end while
      throw new ArgumentOutOfRangeException( );
      } // end get
    } // end indexer
 
    // constructor
    public LinkedList()
    {
    }
 
    // methods
    public void Add(T data)
    {
      if (headNode = = null)
      {
        headNode = new Node<T>(data);
      }
      else
      {
        headNode = headNode.Add(new Node<T>(data));
      }
    }
 
    public override string ToString( )
    {
      if (this.headNode != null)
      {
        return this.headNode.ToString( );
      }
      else
      {
        return string.Empty;
      }
    }
 
    // Implement IEnumerable required method
    // iterate through the node (which is enumerable)
    // and yield up the data from each node returned
    IEnumerator<T> IEnumerable<T>.GetEnumerator( )
    {
      foreach (Node<T> node in this.headNode)
      {
        yield return node.Data;
      }
    }
 
    System.Collections.IEnumerator 
      System.Collections.IEnumerable.GetEnumerator()
    {
      throw new NotImplementedException();
    }
  }
 
  class Program
  {
    private static void DisplayList<T>
      (string intro, LinkedList<T> theList)
      where T : IComparable<T>
    {
      Console.WriteLine(intro + ": " + theList);
    }
 
    // entry point
    static void Main(string[ ] args)
    {
      LinkedList<Pilgrim> pilgrims = new LinkedList<Pilgrim>( );
      pilgrims.Add(new Pilgrim("The Knight"));
      pilgrims.Add(new Pilgrim("The Miller"));
      pilgrims.Add(new Pilgrim("The Reeve"));
      pilgrims.Add(new Pilgrim("The Cook"));
      pilgrims.Add(new Pilgrim("The Man of Law"));
      DisplayList<Pilgrim>("Pilgrims", pilgrims);
      Console.WriteLine("Iterate through pilgrims...");
    
      // Now that the linked list is enumerable, we can put
      // it into a foreach loop
      foreach (Pilgrim p in pilgrims)
      {
        Console.WriteLine("The pilgrim's name is " + p.ToString( ));
      }
    }
  }
}

Output:

Pilgrims: The Cook, The Knight, The Man of Law, The Miller, The Reeve
Iterate through pilgrims...
The pilgrim's name is The Cook
The pilgrim's name is The Knight
The pilgrim's name is The Man of Law
The pilgrim's name is The Miller
The pilgrim's name is The Reeve


Previous_Page_.gif Next_Page_.gif

Personal tools