Introduction
This article aims at explaining the Iterator pattern and having a rudimentary implementation of the Iterator pattern in C#. This article is meant for beginners and does not use any language built-in features for iterations.
Background
Having a collection of objects is a very common thing in software development. If we have a collection of objects, then we might also find ourselves in need to traverse this collection. Most languages provide traversal techniques over basic collection types. C# also contains some special container types capable of holding a collection of values (example: List
s, and ArrayList
s in C#). These specialized containers also come with the possibility of getting iterated. C# container classes are the best examples of how the iterator pattern is implemented.
Note: We will not be using any of these techniques in this article.
If we want the underlying working mechanism of these iterator objects, then we will perhaps need to understand the Iterator pattern first. The idea behind the Iterator pattern is that we decouple the actual collection object from the traversal logic. This will make the collection object lighter as it does not have to deal with all the iteration related functionalities and from the user's point of view, there is a clear separation between the collection and how the collection is being iterated. Also, the user will not have to worry about keeping track of the number of items traversed, remaining, and whether to check for boundary conditions as all this is already being done in the iterator object (as these things will depend on the underlying structure and implementation of the collection object).
GoF defines the Iterator pattern as "Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation". To visualize the GoF design (slightly modified as per our implementation):
Using the Code
Before jumping on to the implementation, let us try to see what each class in this diagram represents:
IIterator
: This is an interface that defines the methods for accessing and traversing elements. MyIterator
: This is ConcreteIterator
, this will implement the Iterator interface and keep track of the current position in the traversal of the aggregate object. IAggregate
: This is an interface that defines methods for creating an Iterator
object. MyAggregate
: This is the ConcreteAggregate
object, i.e., the real collection lies inside this. This class implements the IAggregate
creation interface.
Creating the Iterator Interface
So now let us try to implement this pattern by implementing one class at a time. Let us start by writing the IIterator
interface. This interface should provide the methods for accessing and traversing the elements of the collection object.
Implementation of the IIterator
:
interface IIterator
{
string FirstItem { get;}
string NextItem{ get;}
string CurrentItem{ get;}
bool IsDone { get;}
}
Creating the Interface for an Aggregate (Collection) Object
Once we have the IIterator
ready, let's have the interface IAggregate
. This will simply contain the method to create the iterator.
Implementation of IAggregate
:
interface IAggregate
{
IIterator GetIterator();
string this[int itemIndex]{set;get;}
int Count{get;}
}
Writing the Concrete Aggregate (Collection) Object
Now that we have both the interfaces ready, we can now define the concrete class that will hold a collection of objects. Let's have a simple class that will hold a collection of string
values. We will use our iterator to get hold of these string
values.
Implementation of MyAggregate
:
class MyAggregate : IAggregate
{
List<string> values_ = null;
public MyAggregate()
{
values_ = new List<string>();
}
#region IAggregate Members
public IIterator GetIterator()
{
return new MyIterator(this);
}
#endregion
public string this[int itemIndex]
{
get
{
if (itemIndex < values_.Count)
{
return values_[itemIndex];
}
else
{
return string.Empty;
}
}
set
{
values_.Add(value);
}
}
public int Count
{
get
{
return values_.Count;
}
}
}</string>
Implementing the Concrete Iterator
Let us now implement the MyIterator
, which is the concrete class for IIterator
. The actual logic of iterating through the values of the concrete collection class will be in this class.
Implementation of MyIterator
:
class MyIterator : IIterator
{
IAggregate aggregate_ = null;
int currentIndex_ = 0;
public MyIterator(IAggregate aggregate)
{
aggregate_ = aggregate;
}
#region IIterator Members
public string FirstItem
{
get
{
currentIndex_ = 0;
return aggregate_[currentIndex_];
}
}
public string NextItem
{
get
{
currentIndex_ += 1;
if (IsDone == false)
{
return aggregate_[currentIndex_];
}
else
{
return string.Empty;
}
}
}
public string CurrentItem
{
get
{
return aggregate_[currentIndex_];
}
}
public bool IsDone
{
get
{
if (currentIndex_ < aggregate_.Count)
{
return false;
}
return true;
}
}
#endregion
}
So now, we have all the building blocks ready for a simple and rudimentary implementation of the Iterator pattern. Let's see how we can use the iterator to access the values of a collection.
Here is the implementation for Main
:
class Program
{
static void Main(string[] args)
{
MyAggregate aggr = new MyAggregate();
aggr[0] = "1";
aggr[1] = "2";
aggr[2] = "3";
aggr[3] = "4";
aggr[4] = "5";
aggr[5] = "6";
aggr[6] = "7";
aggr[7] = "8";
aggr[8] = "9";
aggr[9] = "10";
IIterator iter = aggr.GetIterator();
for (string s = iter.FirstItem; iter.IsDone == false; s = iter.NextItem )
{
Console.WriteLine(s);
}
}
}
Now we have a simple implementation of the Iterator pattern in place. There are a lot of possible optimizations possible in the code but the intent here is to explain the Iterator pattern so the code is written in a simple (and perhaps not so efficient) manner.
Points of Interest
The .NET Framework and C# language has the Iterator pattern embedded deep in its code. The IEnumerable
interface is in fact the facilitator of the Iterator pattern. Generics and Collection classes in C# can be iterated through an enumerator which is in fact an Iterator pattern implementation.
We have not seen the C# and .NET specific implementations of the Iterator pattern in this article. Using the language and framework built-in iterators is definitely more efficient and less error prone. The idea behind this article is to understand how the Iterator pattern works and we implemented a simple Iterator pattern in C# .
History
- 7th April, 2012: First version