German Wear Discount Shop - Click Here Write for Dotnet-friends and earn for your each submission [Dot]Net-Friends
Skip Navigation Links
Home
Latest
Fast Code
Articles
Tutorials
Online Resources
Forums
Login   | Hi, Guest


Iterators in C# 2.0

Written by omerkamal on Mar 10, 2007
an other new specification standard of C# 2.0

Explanation:

The C# foreach statement is used to iterate over the elements of an enumerable collection. In order to be enumerable, a collection must have a parameterless GetEnumerator method that returns an enumerator. Generally, enumerators are difficult to implement, but the task is significantly simplified with iterators.
An iterator is a statement block that yields an ordered sequence of values. An iterator is distinguished from a normal statement block by the presence of one or more yield statements:
·         The yield return statement produces the next value of the iteration.
·         The yield break statement indicates that the iteration is complete.
An iterator can be used as the body of a function member as long as the return type of the function member is one of the enumerator interfaces or one of the enumerable interfaces:
·         The enumerator interfaces are System.Collections.IEnumerator and types constructed from System.Collections.Generic.IEnumerator.
·         The enumerable interfaces are System.Collections.IEnumerable and types constructed from System.Collections.Generic.IEnumerable.
It is important to understand that an iterator is not a kind of member, but is a means of implementing a function member. A member implemented via an iterator can be overridden or overloaded by other members which may or may not be implemented with iterators.
The following Stack class implements its GetEnumerator method using an iterator. The iterator enumerates the elements of the stack in top to bottom order.
using System.Collections.Generic;
public class Stack: IEnumerable
{
      T[] items;
      int count;
      public void Push(T data) {...}
      public T Pop() {...}
      public IEnumerator GetEnumerator() {
            for (int i = count – 1; i >= 0; --i) {
                  yield return items[i];
            }
      }
}
The presence of the GetEnumerator method makes Stack an enumerable type, allowing instances of Stack to be used in a foreach statement. The following example pushes the values 0 through 9 onto an integer stack and then uses a foreach loop to display the values in top to bottom order.
using System;
class Test
{
      static void Main() {
            Stack stack = new Stack();
            for (int i = 0; i < 10; i++) stack.Push(i);
            foreach (int i in stack) Console.Write("{0} ", i);
            Console.WriteLine();
      }
}
The output of the example is:
9 8 7 6 5 4 3 2 1 0
The foreach statement implicitly calls a collection’s parameterless GetEnumerator method to obtain an enumerator. There can only be one such parameterless GetEnumerator method defined by a collection, yet it is often appropriate to have multiple ways of enumerating, and ways of controlling the enumeration through parameters. In such cases, a collection can use iterators to implement properties or methods that return one of the enumerable interfaces. For example, Stack might introduce two new properties, TopToBottom and BottomToTop, of type IEnumerable:
using System.Collections.Generic;
public class Stack: IEnumerable
{
      T[] items;
      int count;
      public void Push(T data) {...}
      public T Pop() {...}
      public IEnumerator GetEnumerator() {
            for (int i = count – 1; i >= 0; --i) {
                  yield return items[i];
            }
      }
      public IEnumerable TopToBottom {
            get {
                  return this;
            }
      }
      public IEnumerable BottomToTop {
            get {
                  for (int i = 0; i < count; i++) {
                        yield return items[i];
                  }
            }
      }
}
The get accessor for the TopToBottom property just returns this since the stack itself is an enumerable. The BottomToTop property returns an enumerable implemented with a C# iterator. The following example shows how the properties can be used to enumerate stack elements in either order:
using System;
class Test
{
      static void Main() {
            Stack stack = new Stack();
            for (int i = 0; i < 10; i++) stack.Push(i);
            foreach (int i in stack.TopToBottom) Console.Write("{0} ", i);
            Console.WriteLine();
            foreach (int i in stack.BottomToTop) Console.Write("{0} ", i);
            Console.WriteLine();
      }
}
Of course, these properties can be used outside of a foreach statement as well. The following example passes the results of invoking the properties to a separate Print method. The example also shows an iterator used as the body of a FromToBy method that takes parameters:
using System;
using System.Collections.Generic;
class Test
{
      static void Print(IEnumerable collection) {
            foreach (int i in collection) Console.Write("{0} ", i);
            Console.WriteLine();
      }
      static IEnumerable FromToBy(int from, int to, int by) {
            for (int i = from; i <= to; i += by) {
                  yield return i;
            }
      }
      static void Main() {
            Stack stack = new Stack();
            for (int i = 0; i < 10; i++) stack.Push(i);
            Print(stack.TopToBottom);
            Print(stack.BottomToTop);
            Print(FromToBy(10, 20, 2));
      }
}
The output of the example is:
9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9
20
The generic and non-generic enumerable interfaces contain a single member, a GetEnumerator method that takes no arguments and returns an enumerator interface. An enumerable acts as an enumerator factory. Properly implemented enumerables generate independent enumerators each time their GetEnumerator method is called. Assuming the internal state of the enumerable has not changed between two calls to GetEnumerator, the two enumerators returned should produce the same set of values in the same order. This should hold even if the lifetime of the enumerators overlap as in the following code sample:
using System;
using System.Collections.Generic;
class Test
{
      static IEnumerable FromTo(int from, int to) {
            while (from <= to) yield return from++;
      }
      static void Main() {
            IEnumerable e = FromTo(1, 10);
            foreach (int x in e) {
                  foreach (int y in e) {
                        Console.Write("{0,3} ", x * y);
                  }
                  Console.WriteLine();
            }
      }
}
The code above prints a simple multiplication table of the integers 1 through 10. Note that the FromTo method is invoked only once to generate the enumerable e. However, e.GetEnumerator() is invoked multiple times (by the foreach statements) to generate multiple equivalent enumerators. These enumerators all encapsulate the iterator code specified in the declaration of FromTo. Note that the iterator code modifies the from parameter. Nevertheless, the enumerators act independently because each enumerator is given its own copy of the from and to parameters. The sharing of transient state between enumerators is one of several common subtle flaws that should be avoided when implementing enumerables and enumerators. C# iterators are designed to help avoid these problems and to implement robust enumerables and enumerators in a simple intuitive way.
Visitors/Readers Comments
(for questions please use The Forum)



Ranjith Kumar S.
Good Helped me to understand IEnumerator  GREAT WORK !!!

17/09/2007 00:31:13 UTC

Mathivanan K
Good..

23/10/2007 03:22:19 UTC

Guru
G8 explanation.

26/10/2007 12:01:30 UTC

Channabasappa
Good Article.................. Found it helpful..............................                     :)

18/06/2008 04:30:08 UTC




Add your Comments

Name:  
Message:
Note: For faster response please use Forums >> for your questions instead of the comments area! (Admin)