Dofactory.com
Dofactory.com

C# Iterator Design Pattern

The Iterator design pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

C# code examples of the Iterator design pattern is provided in 3 forms:

Frequency of use:
high
C# Design Patterns

UML class diagram

#

A visualization of the classes and objects participating in this pattern.

Participants

#

The classes and objects participating in this pattern include:

  • Iterator (AbstractIterator)
    • defines an interface for accessing and traversing elements.
  • ConcreteIterator (Iterator)
    • implements the Iterator interface.
    • keeps track of the current position in the traversal of the aggregate.
  • Aggregate (AbstractCollection)
    • defines an interface for creating an Iterator object
  • ConcreteAggregate (Collection)
    • implements the Iterator creation interface to return an instance of the proper ConcreteIterator

Structural code in C#

#

This structural code demonstrates the Iterator pattern which provides for a way to traverse (iterate) over a collection of items without detailing the underlying structure of the collection.

copied to clipboard
using System;
using System.Collections.Generic;

namespace Iterator.Structural
{
 /// <summary>
 /// Iterator Design Pattern
 /// </summary>

 public class Program
 {
 public static void Main(string[] args)
 {
 ConcreteAggregate a = new ConcreteAggregate();
 a[0] = "Item A";
 a[1] = "Item B";
 a[2] = "Item C";
 a[3] = "Item D";

 // Create Iterator and provide aggregate

 Iterator i = a.CreateIterator();

 Console.WriteLine("Iterating over collection:");

 object item = i.First();

 while (item != null)
 {
 Console.WriteLine(item);
 item = i.Next();
 }

 // Wait for user

 Console.ReadKey();
 }
 }

 /// <summary>
 /// The 'Aggregate' abstract class
 /// </summary>

 public abstract class Aggregate
 {
 public abstract Iterator CreateIterator();
 }

 /// <summary>
 /// The 'ConcreteAggregate' class
 /// </summary>

 public class ConcreteAggregate : Aggregate
 {
 List<object> items = new List<object>();

 public override Iterator CreateIterator()
 {
 return new ConcreteIterator(this);
 }

 // Get item count

 public int Count
 {
 get { return items.Count; }
 }

 // Indexer

 public object this[int index]
 {
 get { return items[index]; }
 set { items.Insert(index, value); }
 }
 }

 /// <summary>
 /// The 'Iterator' abstract class
 /// </summary>

 public abstract class Iterator
 {
 public abstract object First();
 public abstract object Next();
 public abstract bool IsDone();
 public abstract object CurrentItem();
 }

 /// <summary>
 /// The 'ConcreteIterator' class
 /// </summary>

 public class ConcreteIterator : Iterator
 {
 ConcreteAggregate aggregate;
 int current = 0;

 // Constructor

 public ConcreteIterator(ConcreteAggregate aggregate)
 {
 this.aggregate = aggregate;
 }

 // Gets first iteration item

 public override object First()
 {
 return aggregate[0];
 }

 // Gets next iteration item

 public override object Next()
 {
 object ret = null;
 if (current < aggregate.Count - 1)
 {
 ret = aggregate[++current];
 }

 return ret;
 }

 // Gets current iteration item

 public override object CurrentItem()
 {
 return aggregate[current];
 }

 // Gets whether iterations are complete

 public override bool IsDone()
 {
 return current >= aggregate.Count;
 }
 }
}
using System;
using System.Collections.Generic;

namespace Iterator.Structural
{
 /// <summary>
 /// Iterator Design Pattern
 /// </summary>

 public class Program
 {
 public static void Main(string[] args)
 {
 ConcreteAggregate a = new ConcreteAggregate();
 a[0] = "Item A";
 a[1] = "Item B";
 a[2] = "Item C";
 a[3] = "Item D";

 // Create Iterator and provide aggregate

 Iterator i = a.CreateIterator();

 Console.WriteLine("Iterating over collection:");

 object item = i.First();

 while (item != null)
 {
 Console.WriteLine(item);
 item = i.Next();
 }

 // Wait for user

 Console.ReadKey();
 }
 }

 /// <summary>
 /// The 'Aggregate' abstract class
 /// </summary>

 public abstract class Aggregate
 {
 public abstract Iterator CreateIterator();
 }

 /// <summary>
 /// The 'ConcreteAggregate' class
 /// </summary>

 public class ConcreteAggregate : Aggregate
 {
 List<object> items = new List<object>();

 public override Iterator CreateIterator()
 {
 return new ConcreteIterator(this);
 }

 // Get item count

 public int Count
 {
 get { return items.Count; }
 }

 // Indexer

 public object this[int index]
 {
 get { return items[index]; }
 set { items.Insert(index, value); }
 }
 }

 /// <summary>
 /// The 'Iterator' abstract class
 /// </summary>

 public abstract class Iterator
 {
 public abstract object First();
 public abstract object Next();
 public abstract bool IsDone();
 public abstract object CurrentItem();
 }

 /// <summary>
 /// The 'ConcreteIterator' class
 /// </summary>

 public class ConcreteIterator : Iterator
 {
 ConcreteAggregate aggregate;
 int current = 0;

 // Constructor

 public ConcreteIterator(ConcreteAggregate aggregate)
 {
 this.aggregate = aggregate;
 }

 // Gets first iteration item

 public override object First()
 {
 return aggregate[0];
 }

 // Gets next iteration item

 public override object Next()
 {
 object ret = null;
 if (current < aggregate.Count - 1)
 {
 ret = aggregate[++current];
 }

 return ret;
 }

 // Gets current iteration item

 public override object CurrentItem()
 {
 return aggregate[current];
 }

 // Gets whether iterations are complete

 public override bool IsDone()
 {
 return current >= aggregate.Count;
 }
 }
}
Output
Iterating over collection:
Item A
Item B
Item C
Item D

Real-world code in C#

#

This real-world code demonstrates the Iterator pattern which is used to iterate over a collection of items and skip a specific number of items each iteration.

copied to clipboard
using System;
using System.Collections.Generic;

namespace Iterator.RealWorld
{
 /// <summary>
 /// Iterator Design Pattern
 /// </summary>

 public class Program
 {
 public static void Main(string[] args)
 {
 // Build a collection

 Collection collection = new Collection();
 collection[0] = new Item("Item 0");
 collection[1] = new Item("Item 1");
 collection[2] = new Item("Item 2");
 collection[3] = new Item("Item 3");
 collection[4] = new Item("Item 4");
 collection[5] = new Item("Item 5");
 collection[6] = new Item("Item 6");
 collection[7] = new Item("Item 7");
 collection[8] = new Item("Item 8");

 // Create iterator

 Iterator iterator = collection.CreateIterator();

 // Skip every other item

 iterator.Step = 2;

 Console.WriteLine("Iterating over collection:");

 for (Item item = iterator.First();
 !iterator.IsDone; item = iterator.Next())
 {
 Console.WriteLine(item.Name);
 }

 // Wait for user

 Console.ReadKey();
 }
 }
 /// <summary>
 /// A collection item
 /// </summary>

 public class Item
 {
 string name;

 // Constructor

 public Item(string name)
 {
 this.name = name;
 }

 public string Name
 {
 get { return name; }
 }
 }

 /// <summary>
 /// The 'Aggregate' interface
 /// </summary>

 public interface IAbstractCollection
 {
 Iterator CreateIterator();
 }

 /// <summary>
 /// The 'ConcreteAggregate' class
 /// </summary>

 public class Collection : IAbstractCollection
 {
 List<Item> items = new List<Item>();

 public Iterator CreateIterator()
 {
 return new Iterator(this);
 }

 // Gets item count

 public int Count
 {
 get { return items.Count; }
 }

 // Indexer

 public Item this[int index]
 {
 get { return items[index]; }
 set { items.Add(value); }
 }
 }

 /// <summary>
 /// The 'Iterator' interface
 /// </summary>

 public interface IAbstractIterator
 {
 Item First();
 Item Next();
 bool IsDone { get; }
 Item CurrentItem { get; }
 }

 /// <summary>
 /// The 'ConcreteIterator' class
 /// </summary>

 public class Iterator : IAbstractIterator
 {
 Collection collection;
 int current = 0;
 int step = 1;

 // Constructor

 public Iterator(Collection collection)
 {
 this.collection = collection;
 }

 // Gets first item

 public Item First()
 {
 current = 0;
 return collection[current] as Item;
 }

 // Gets next item

 public Item Next()
 {
 current += step;
 if (!IsDone)
 return collection[current] as Item;
 else
 return null;
 }

 // Gets or sets stepsize

 public int Step
 {
 get { return step; }
 set { step = value; }
 }

 // Gets current iterator item

 public Item CurrentItem
 {
 get { return collection[current] as Item; }
 }

 // Gets whether iteration is complete

 public bool IsDone
 {
 get { return current >= collection.Count; }
 }
 }
}
using System;
using System.Collections.Generic;

namespace Iterator.RealWorld
{
 /// <summary>
 /// Iterator Design Pattern
 /// </summary>

 public class Program
 {
 public static void Main(string[] args)
 {
 // Build a collection

 Collection collection = new Collection();
 collection[0] = new Item("Item 0");
 collection[1] = new Item("Item 1");
 collection[2] = new Item("Item 2");
 collection[3] = new Item("Item 3");
 collection[4] = new Item("Item 4");
 collection[5] = new Item("Item 5");
 collection[6] = new Item("Item 6");
 collection[7] = new Item("Item 7");
 collection[8] = new Item("Item 8");

 // Create iterator

 Iterator iterator = collection.CreateIterator();

 // Skip every other item

 iterator.Step = 2;

 Console.WriteLine("Iterating over collection:");

 for (Item item = iterator.First();
 !iterator.IsDone; item = iterator.Next())
 {
 Console.WriteLine(item.Name);
 }

 // Wait for user

 Console.ReadKey();
 }
 }
 /// <summary>
 /// A collection item
 /// </summary>

 public class Item
 {
 string name;

 // Constructor

 public Item(string name)
 {
 this.name = name;
 }

 public string Name
 {
 get { return name; }
 }
 }

 /// <summary>
 /// The 'Aggregate' interface
 /// </summary>

 public interface IAbstractCollection
 {
 Iterator CreateIterator();
 }

 /// <summary>
 /// The 'ConcreteAggregate' class
 /// </summary>

 public class Collection : IAbstractCollection
 {
 List<Item> items = new List<Item>();

 public Iterator CreateIterator()
 {
 return new Iterator(this);
 }

 // Gets item count

 public int Count
 {
 get { return items.Count; }
 }

 // Indexer

 public Item this[int index]
 {
 get { return items[index]; }
 set { items.Add(value); }
 }
 }

 /// <summary>
 /// The 'Iterator' interface
 /// </summary>

 public interface IAbstractIterator
 {
 Item First();
 Item Next();
 bool IsDone { get; }
 Item CurrentItem { get; }
 }

 /// <summary>
 /// The 'ConcreteIterator' class
 /// </summary>

 public class Iterator : IAbstractIterator
 {
 Collection collection;
 int current = 0;
 int step = 1;

 // Constructor

 public Iterator(Collection collection)
 {
 this.collection = collection;
 }

 // Gets first item

 public Item First()
 {
 current = 0;
 return collection[current] as Item;
 }

 // Gets next item

 public Item Next()
 {
 current += step;
 if (!IsDone)
 return collection[current] as Item;
 else
 return null;
 }

 // Gets or sets stepsize

 public int Step
 {
 get { return step; }
 set { step = value; }
 }

 // Gets current iterator item

 public Item CurrentItem
 {
 get { return collection[current] as Item; }
 }

 // Gets whether iteration is complete

 public bool IsDone
 {
 get { return current >= collection.Count; }
 }
 }
}
Output
Iterating over collection:
Item 0
Item 2
Item 4
Item 6
Item 8

.NET Optimized code in C#

#

The .NET optimized code demonstrates the same code as above but uses more modern C# and .NET features.

Here is an elegant C# Iterator solution.

copied to clipboard
namespace Iterator.NetOptimized;

using static System.Console;

using System.Collections;
using System.Collections.Generic;

/// <summary>
/// Iterator Design Pattern
/// </summary>
public class Program
{
 public static void Main()
 {
 // Create and item collection
 ItemCollection<Item> items = [
 new("Item 0"),
 new("Item 1"),
 new("Item 2"),
 new("Item 3"),
 new("Item 4"),
 new("Item 5"),
 new("Item 6"),
 new("Item 7"),
 new("Item 8")
 ];

 WriteLine("Iterate front to back");
 foreach (var item in items)
 {
 WriteLine(item.Name);
 }

 WriteLine("\nIterate back to front");
 foreach (var item in items.BackToFront)
 {
 WriteLine(item.Name);
 }
 WriteLine();

 // Iterate given range and step over even ones
 WriteLine("\nIterate range (1-7) in steps of 2");
 foreach (var item in items.FromToStep(1, 7, 2))
 {
 WriteLine(item.Name);
 }
 WriteLine();

 // Wait for user
 ReadKey();
 }
}

/// <summary>
/// The 'ConcreteAggregate' class
/// </summary>
/// <typeparam name="T">Collection item type</typeparam>
public class ItemCollection<T> : IEnumerable<T>
{
 private readonly List<T> items = [];

 public void Add(T t) => items.Add(t);

 // The 'ConcreteIterator'
 public IEnumerator<T> GetEnumerator()
 {
 for (int i = 0; i < Count; i++)
 {
 yield return items[i];
 }
 }

 public IEnumerable<T> FrontToBack { get => this; }

 public IEnumerable<T> BackToFront
 {
 get 
 {
 for (int i = Count - 1; i >= 0; i--)
 {
 yield return items[i];
 }
 }
 }

 public IEnumerable<T> FromToStep(int from, int to, int step)
 {
 for (int i = from; i <= to; i += step)
 {
 yield return items[i];
 }
 }

 // Gets number of items
 public int Count { get => items.Count; }

 // System.Collections.IEnumerable member implementation
 IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

/// <summary>
/// The collection item
/// </summary>
internal record Item (string Name);
namespace Iterator.NetOptimized;

using static System.Console;

using System.Collections;
using System.Collections.Generic;

/// <summary>
/// Iterator Design Pattern
/// </summary>
public class Program
{
 public static void Main()
 {
 // Create and item collection
 ItemCollection<Item> items = [
 new("Item 0"),
 new("Item 1"),
 new("Item 2"),
 new("Item 3"),
 new("Item 4"),
 new("Item 5"),
 new("Item 6"),
 new("Item 7"),
 new("Item 8")
 ];

 WriteLine("Iterate front to back");
 foreach (var item in items)
 {
 WriteLine(item.Name);
 }

 WriteLine("\nIterate back to front");
 foreach (var item in items.BackToFront)
 {
 WriteLine(item.Name);
 }
 WriteLine();

 // Iterate given range and step over even ones
 WriteLine("\nIterate range (1-7) in steps of 2");
 foreach (var item in items.FromToStep(1, 7, 2))
 {
 WriteLine(item.Name);
 }
 WriteLine();

 // Wait for user
 ReadKey();
 }
}

/// <summary>
/// The 'ConcreteAggregate' class
/// </summary>
/// <typeparam name="T">Collection item type</typeparam>
public class ItemCollection<T> : IEnumerable<T>
{
 private readonly List<T> items = [];

 public void Add(T t) => items.Add(t);

 // The 'ConcreteIterator'
 public IEnumerator<T> GetEnumerator()
 {
 for (int i = 0; i < Count; i++)
 {
 yield return items[i];
 }
 }

 public IEnumerable<T> FrontToBack { get => this; }

 public IEnumerable<T> BackToFront
 {
 get 
 {
 for (int i = Count - 1; i >= 0; i--)
 {
 yield return items[i];
 }
 }
 }

 public IEnumerable<T> FromToStep(int from, int to, int step)
 {
 for (int i = from; i <= to; i += step)
 {
 yield return items[i];
 }
 }

 // Gets number of items
 public int Count { get => items.Count; }

 // System.Collections.IEnumerable member implementation
 IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

/// <summary>
/// The collection item
/// </summary>
internal record Item (string Name);
Output
Iterating over collection:
Item 0
Item 2
Item 4
Item 6
Item 8



Last updated on Mar 17, 2024

Want to know more?


Learn how to build .NET applications in 33 days with design patterns, ultra clean architecture, and more.

Learn more about our Dofactory .NET developer package.


Guides


vsn 3.2

AltStyle によって変換されたページ (->オリジナル) /