Iterator Pattern in C#: From Basics to Advanced

Laks Tutor
3 min readAug 17, 2023

--

The Iterator Pattern is a behavioral design pattern that provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation. In C#, the Iterator Pattern is deeply ingrained in the language through the IEnumerable and IEnumerator interfaces. In this blog post, we'll explore the Iterator Pattern in C#, starting from the basics and progressing to advanced scenarios.

Basics of Iterator Pattern

Concept

The Iterator Pattern provides a mechanism to traverse through a collection without the need to understand or expose its underlying structure. It abstracts the process of iteration, allowing different collections to be navigated and accessed in a uniform way.

Participants

  1. Iterator: Defines an interface for accessing and traversing elements.
  2. ConcreteIterator: Implements the Iterator interface and keeps track of the current position in the traversal of the aggregate.
  3. Aggregate: Defines an interface for creating an Iterator object.
  4. ConcreteAggregate: Implements the Aggregate interface and returns an instance of the ConcreteIterator.

Simple Implementation

Let’s start with a basic example: iterating over a collection of books.

// Aggregate
public interface IBookCollection
{
Iterator CreateIterator();
}

// ConcreteAggregate
public class BookCollection : IBookCollection
{
private List<string> _titles = new List<string>();
public void Add(string title)
{
_titles.Add(title);
}
public Iterator CreateIterator()
{
return new BookIterator(this);
}
public int Count => _titles.Count;
public string this[int index]
{
get { return _titles[index]; }
}
}
// Iterator
public abstract class Iterator
{
public abstract string First();
public abstract string Next();
public abstract bool IsDone();
public abstract string CurrentItem();
}
// ConcreteIterator
public class BookIterator : Iterator
{
private BookCollection _books;
private int _current = 0;
public BookIterator(BookCollection books)
{
_books = books;
}
public override string First()
{
return _books[0];
}
public override string Next()
{
_current++;
if (IsDone())
return null;
else
return _books[_current];
}
public override bool IsDone()
{
return _current >= _books.Count;
}
public override string CurrentItem()
{
return _books[_current];
}
}
// Client
var books = new BookCollection();
books.Add("Design Patterns");
books.Add("Clean Code");
books.Add("Refactoring");
var iterator = books.CreateIterator();
while (!iterator.IsDone())
{
Console.WriteLine(iterator.CurrentItem());
iterator.Next();
}

Advanced Usage of Iterator Pattern

1. C# Built-in Support

C# provides built-in support for the Iterator Pattern through the IEnumerable and IEnumerator interfaces. The yield keyword in C# makes it even easier to implement custom iterators.

public class BookCollection : IEnumerable<string>
{
private List<string> _titles = new List<string>();

public void Add(string title)
{
_titles.Add(title);
}
public IEnumerator<string> GetEnumerator()
{
foreach (var title in _titles)
{
yield return title;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
// Client
var books = new BookCollection();
books.Add("Design Patterns");
books.Add("Clean Code");
books.Add("Refactoring");
foreach (var book in books)
{
Console.WriteLine(book);
}

2. Two-way Iterators

While the basic iterator allows forward traversal, you can extend the pattern to support bidirectional traversal, i.e., both forward and backward.

3. Composite Iterators

If you have a composite structure, such as a tree, you can design an iterator to traverse it. For instance, a depth-first or breadth-first iterator for a tree structure.

4. Filtered Iterators

You can design iterators that only return specific elements based on a condition, effectively filtering the collection.

5. Lazy Iterators

Lazy iterators don’t compute the value of the next item until it’s requested. This is particularly useful for large collections or when computing the next item is resource-intensive.

Conclusion

The Iterator Pattern is a powerful design pattern that abstracts the process of iterating over a collection, making the underlying structure of the collection irrelevant to the client. With C#’s built-in support for the pattern, implementing custom iterators is straightforward and elegant. Whether you’re dealing with simple lists or complex composite structures, the Iterator Pattern provides a consistent and clean way to traverse and access elements.

--

--

Laks Tutor

Software Architect & .NET expert. Specializing in Docker & Kubernetes. Freelance corporate trainer. Shaping tech & sharing insights on Medium.