C# Design Patterns: Iterator

Biswajit Sahoo
5 min readJan 1, 2024

--

Iterator C# Design Pattern

Thanks for visiting this article. Please scroll down for the bite-sized explanation of this pattern.

Definition

The Iterator pattern is a behavioral design pattern that provides a way to access elements of an object without exposing the underlying representation. (Arrays, List, Trees, Graphs, etc)

This design pattern is suitable for use cases where the client needs to deal with complex collections that can evolve/update over time.

Why do we need an Iterator pattern?

Each collection no matter how complex the data structures it is, should provide a way of accessing its elements for other dependent codes to go over them.

For lists and arrays, it is simple to just loop over the collection and access the elements, but what if the collection is of a tree type, or graph type? One time you are okay with using depth-first traversal, yet someday you need to update the code to use breadth-first traversal or a random way of accessing specific elements.

That means the client code needs to be aware of the collection type and needs to be updated for every type of traversal requirement.

The iterator pattern solves this exact case.

Let’s understand this from an example

Consider, that we have an inventory application in a bookstore, that allows readers to browse books organized on the BookShelf.

Let’s define a class Book.cs to hold the titles and author names.

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

Book.cs class

We’ll create a class called BookShelf.cs that manages the collection of books.

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

BookShelf.cs class

Then we’ll create a client class called BooksViewer.cs that shows all the book collections available

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

BooksViewer.cs client class

There we go, the BooksViewer can show all the books available on the bookshelf.

Now, what if the book collection gets changed to a tree or graph type? 😟

❌ Does that mean we have to modify the client logic to print out the book names? 😩.

❌ What if the collection gets updated to another data structure again … if we continue adding and modifying stuff to the client BooksViewer, how long before the client class becomes clunky and messy? 😨

The only thing BooksViewer should be caring about is displaying the books from the collection and not managing traversal logic for the collection.

And that’s where the Iterator pattern comes to help. 👐

Implementing the Iterator Pattern

The iterator pattern requires defining two interfaces.

1️⃣ one interface for the iterator class itself, which allows traversal over the collection, and returns the next item.

2️⃣ and another interface that will return an object for iterator type, called an aggregate.

Let’s call the iterator interface IIterator.cs which will have two methods, one for checking if we have the next item in the collection and a second for getting the next item.

IIterator.cs interface

And the aggregator interface as IAggregate.cs which will have a single method that returns the IIterator type object.

IAggregate.cs interface

The aggregate would be the class that creates and returns the iterator object, which would be the BookShelf.cs but we do not have an iterator class yet, which we will define as BooksIterator.cs.

👉 Practically many prefer to keep the iterator class as a nested class under the aggregator, which makes sense as the aggregator contains the collection for the iterator to iterate on, but in some cases, it is advisable to have the iterator defined as a separate class, as per project’s defined code conventions.

Modifying the BookShelf.cs to implement the IAggregate interface and we will have the BooksIterator.cs as a nested class implementing the IIterator interface.

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

BookShelf.cs implementing IAggregate interface and containing BooksIterator

With that, now we have the collection and iterator abstracted away from other classes.

We will modify the client BooksViewer to use the aggregate and iterator to list out all the books for the readers.

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

Updated BooksViewer.cs client class using concrete IAggregate and IIterator instances

And there you go, a much cleaner approach to traversing over a collection and accessing the elements. 🙌

✅ As the collection type is abstracted away, it can be modified to any complex data structure type based on the requirements, keeping the client code unchanged.

That’s how by using the iterator pattern, the internal management for a complex collection data structure stays abstracted from the clients depending on them, which allows more isolated updates to the collection class as per requirement without the need to modify the dependent clients, or how they interact. 😃 👍

In C# the iterator pattern is built-in and provided in the .NET core library to allow developers to use to generate the code necessary to iterate over a collection as IEnumerable<T> and IEnumerator<T>.

Please visit this link, if interested https://learn.microsoft.com/en-us/dotnet/csharp/iterators

Hope this helped with giving you some clarity on how this pattern can be implemented and used in a real-world scenario.

On the last note. If you like the article please do like and share, and also feel free to provide your valuable comments and feedback.

--

--

Biswajit Sahoo

Professional XR Developer and Gamer. Writes about system designs, and design patterns in C#.