Iterator Pattern in C#: Definition, Examples, Pros, Cons, and Use Cases
The Iterator pattern in C# is a behavioral design pattern that provides a way to sequentially access elements of a collection without exposing its internal structure.
The Iterator pattern allows clients to traverse collections without knowing how the collection is internally implemented. It separates collection management logic from traversal logic, improving encapsulation and maintainability. In C#, the pattern is commonly implemented using the IEnumerable and IEnumerator interfaces. An iterator maintains the current traversal state and provides methods for moving through elements one by one. This pattern is heavily used in collections, LINQ operations, file readers, tree traversal systems, and custom data structures.
Why We Use Iterator Pattern in C#?
We use the Iterator pattern in C# to:
• Traverse collections without exposing internal details
• Provide a standard way to iterate over objects
• Support multiple traversal strategies
• Simplify collection access logic
• Improve encapsulation
• Separate iteration logic from collection logic
• Enable foreach loop support
• Reduce duplicate traversal code
When Should We Use Iterator Pattern in C#?
The Iterator pattern should be used when:
• A collection needs sequential access
• Internal collection structure should remain hidden
• Multiple traversal methods are required
• Collections have complex internal structures
• You want standard iteration support
• Different collection types need a common traversal mechanism
• You want to support foreach iteration
Common Programming Problems Solved by Iterator Pattern
• Traversing custom collections
• Navigating tree structures
• Iterating graph nodes
• Reading streamed data
• Paging through records
• Processing large datasets lazily
• Supporting multiple traversal orders
• Hiding collection implementation details
Structure of Iterator Pattern in C#
Typical participants:
• Iterator Interface
• Concrete Iterator
• Aggregate Interface
• Concrete Aggregate
• Client
Basic workflow:
• Client requests iterator from collection
• Iterator tracks current position
• Client accesses elements sequentially
• Iterator moves to next element until traversal ends
Iterator Pattern Examples in C#
Example 1: Custom Number Collection Iterator
A custom collection should support sequential iteration using foreach.
using System;
using System.Collections;
using System.Collections.Generic;
public class NumberCollection : IEnumerable<int>
{
private List<int> numbers = new List<int>();
public void Add(int number)
{
numbers.Add(number);
}
public IEnumerator<int> GetEnumerator()
{
return numbers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class Program
{
public static void Main()
{
NumberCollection collection = new NumberCollection();
collection.Add(10);
collection.Add(20);
collection.Add(30);
foreach (int number in collection)
{
Console.WriteLine(number);
}
}
}
Example 2: Custom Iterator with Manual Traversal
A collection requires explicit iterator control.
using System;
public interface IIterator
{
bool HasNext();
string Next();
}
public class NameIterator : IIterator
{
private string[] names;
private int position = 0;
public NameIterator(string[] names)
{
this.names = names;
}
public bool HasNext()
{
return position < names.Length;
}
public string Next()
{
return names[position++];
}
}
public class NameCollection
{
private string[] names = { "John", "Alice", "Bob" };
public IIterator CreateIterator()
{
return new NameIterator(names);
}
}
public class Program
{
public static void Main()
{
NameCollection collection = new NameCollection();
IIterator iterator = collection.CreateIterator();
while (iterator.HasNext())
{
Console.WriteLine(iterator.Next());
}
}
}
Example 3: Tree Traversal Iterator
A tree structure should be traversed recursively.
using System;
using System.Collections.Generic;
public class TreeNode
{
public string Value { get; set; }
public List<TreeNode> Children { get; set; }
public TreeNode(string value)
{
Value = value;
Children = new List<TreeNode>();
}
public IEnumerable<TreeNode> Traverse()
{
yield return this;
foreach (var child in Children)
{
foreach (var node in child.Traverse())
{
yield return node;
}
}
}
}
public class Program
{
public static void Main()
{
TreeNode root = new TreeNode("Root");
root.Children.Add(new TreeNode("Child 1"));
root.Children.Add(new TreeNode("Child 2"));
foreach (var node in root.Traverse())
{
Console.WriteLine(node.Value);
}
}
}
Most Known Real-World Use Cases in C#
• foreach loops
• LINQ query execution
• Collection frameworks
• File streaming readers
• XML and JSON parsers
• Tree and graph traversal
• Database result iteration
• Pagination systems
• Lazy-loaded collections
Advantages of Iterator Pattern in C#
• Hides internal collection structure
• Supports standard traversal
• Simplifies client code
• Enables multiple traversal strategies
• Improves encapsulation
• Supports lazy evaluation
• Reduces duplicated iteration logic
• Works naturally with foreach
Disadvantages (Weak Points) of Iterator Pattern in C#
• Adds extra classes/interfaces
• Can increase complexity for small collections
• Traversal state management may become difficult
• Multiple iterators may consume extra memory
• Recursive iterators may impact performance
• Concurrent modifications can cause issues
Comparison with Similar Patterns
| Pattern | Main Purpose | Traversal Support | State Management | Typical Usage | Main Difference from Iterator |
|---|---|---|---|---|---|
| Iterator | Sequential collection traversal | Yes | Inside iterator | Collections, LINQ, foreach | Focuses specifically on traversal abstraction |
| Composite | Represent tree structures | Optional | In tree nodes | UI trees, file systems | Focuses on hierarchical object composition |
| Visitor | Add operations to structures | Usually combined | Visitor object | Compilers, syntax trees | Adds operations rather than traversal abstraction |
| Enumerator | Low-level iteration mechanism | Yes | Enumerator object | .NET collections | Enumerator is the .NET implementation detail of Iterator |
| Observer | Notify subscribers | No | Observer list | Events, messaging | Focuses on event notification instead of traversal |
Simplified UML-Style Structure
| Component | Responsibility |
|---|---|
| Client | Uses iterator to access collection items |
| Iterator | Defines traversal operations |
| ConcreteIterator | Tracks current traversal position |
| Aggregate | Creates iterator objects |
| ConcreteAggregate | Stores collection data |