Mastering the Iterator Pattern for Custom Collections
In this lesson, you will learn how to traverse complex data structures using a uniform interface regardless of how the underlying data is stored.
The Problem of Hidden Structure
Imagine you have a Library class that stores books. Internally, you might use a simple List<Book>, a complex BinaryTree<Book>, or even a linked structure. If you want to allow someone to loop through your library using a foreach statement, you shouldn't force them to understand your internal structure. If you change your storage from a List to a Tree, you shouldn't have to break all the code that loops through your books.
The Uniform Solution
The Iterator pattern solves this by providing a standard way to access elements sequentially. In C#, we use the IEnumerable and IEnumerator interfaces to create this "bridge." By implementing these, you essentially tell the outside world: "I don't care how I store my data, but here is a simple way for you to walk through it one by one."
Consider this simplified implementation:
public class Library : IEnumerable<Book>
{
private Book[] _books = { new Book("C# Basics"), new Book("Design Patterns") };
public IEnumerator<Book> GetEnumerator()
{
// We provide a way to walk through our internal array
foreach (var book in _books)
{
yield return book;
}
}
// Explicit implementation for older compatibility
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
=> GetEnumerator();
}
By adding the yield return keyword, C# automatically generates an iterator object for you. Now, any consumer can use a standard foreach loop:
Library myLibrary = new Library();
foreach (var book in myLibrary)
{
Console.WriteLine(book.Title);
}
The user of your Library class doesn't need to know if you are using an array, a list, or a complex graph. The traversal logic is hidden behind the GetEnumerator interface, keeping your collection logic decoupled from the code that processes the data.
Key Takeaway: The Iterator pattern allows you to provide a consistent foreach access experience to your custom collections while keeping their internal storage structure completely private and swappable.