Data Structures and Algorithms
with Object-Oriented Design Patterns in C# |
In this section we introduce an abstraction called an enumerator. An enumerator provides the means to access one-by-one all the objects in a container. Enumerators are an alternative to using the visitors described in Section .
The Container interface given in Program extends the standard C# IEnumerable interface . The following code fragment defines the IEnumerable interface.
namespace System.Collections { public interface IEnumerable { public IEnumerator GetEnumerator(); } }Simply put, a class that is enumerable provides a method that returns an enumerator.
The idea is that for every concrete container class we will also implement a related class that implements the standard C# IEnumerator interface . The following code fragment defines the IEnumerator interface.
namespace System.Collections { public interface IEnumerator { public bool MoveNext(); public object Current { get; } public void Reset(); } }The interface comprises two methods, MoveNext and Reset, and a property, Current.
In order to understand the desired semantics, it is best to consider first an example which illustrates the use of an enumerator. Consider a concrete container class, say SomeContainer, that implements the Container interface. The following code fragment illustrates the use of the enumerator to access one-by-one the objects contained in the container:
Container c = new SomeContainer(); // ... IEnumerator e = c.GetEnumerator(); while (e.MoveNext()) { object obj = e.Current; Console.WriteLine(obj); } e.Reset();
In order to have the desired effect, the members of the IEnumerator interface must have the following behaviors:
One of the advantages of using an enumerator object which is separate from the container is that it is possible then to have more than one enumerator associated with a given container. This provides greater flexibility than possible using a visitor, since only one visitor can be accepted by a container at any given time. For example, consider the following code fragment:
Container c = new SomeContainer(); // ... IEnumerator e1 = c.GetEnumerator(); while (e1.MoveNext()) { object obj1 = e1.Current; IEnumerator e2 = c.GetEnumerator(); while (e2.MoveNext()) { object obj2 = e2.Current; if (obj1.Equals(obj2)) Console.WriteLine(obj1 + "=" + obj2); } }This code compares all pairs of objects in the container c and prints out those which are equal.
A certain amount of care is required when defining and using enumerators. In order to simplify the implementation of enumerators, we shall assume that while an enumerator is in use, the associated container will not be modified.