Iterators in C#
What are Iterators in C#?
An **Iterator** in C# is a feature that enables looping over collections using **lazy evaluation**. Iterators simplify traversing custom collections by implementing the yield return
and yield break
statements.
Key Features of Iterators
- Used to iterate over collections in a simple and efficient way.
- Utilizes **lazy evaluation**, generating values as they are requested.
- Supports
yield return
to return values one by one. - Can be implemented in **methods, properties, or indexers**.
Using Iterators with IEnumerable
The most common way to use an iterator is to implement IEnumerable
and IEnumerable<T>
.
Example: Implementing an Iterator with IEnumerable
using System;
using System.Collections;
using System.Collections.Generic;
class NumberCollection : IEnumerable
{
public IEnumerator GetEnumerator()
{
for (int i = 1; i <= 5; i++)
{
yield return i;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
// Usage
class Program
{
static void Main()
{
NumberCollection numbers = new NumberCollection();
Console.WriteLine("Numbers:");
foreach (var num in numbers)
{
Console.WriteLine(num);
}
}
}
// Output:
// Numbers:
// 1
// 2
// 3
// 4
// 5
The yield return
statement allows iterating through numbers **without storing all elements in memory**.
Using yield return
in Methods
The yield return
statement allows methods to return values **one at a time** instead of returning all at once.
Example: Using yield return in a Method
using System;
using System.Collections.Generic;
class Program
{
static IEnumerable GetEvenNumbers(int limit)
{
for (int i = 2; i <= limit; i += 2)
{
yield return i;
}
}
static void Main()
{
Console.WriteLine("Even Numbers:");
foreach (var num in GetEvenNumbers(10))
{
Console.WriteLine(num);
}
}
}
// Output:
// Even Numbers:
// 2
// 4
// 6
// 8
// 10
The method GetEvenNumbers()
generates even numbers **only when requested**, reducing memory usage.
Using yield break
to Stop Iteration
The yield break
statement stops an iteration prematurely when a condition is met.
Example: Using yield break in an Iterator
using System;
using System.Collections.Generic;
class Program
{
static IEnumerable GetNumbers(int limit)
{
for (int i = 1; i <= limit; i++)
{
if (i > 5)
yield break; // Stops iteration
yield return i;
}
}
static void Main()
{
Console.WriteLine("Numbers (up to 5):");
foreach (var num in GetNumbers(10))
{
Console.WriteLine(num);
}
}
}
// Output:
// Numbers (up to 5):
// 1
// 2
// 3
// 4
// 5
The **yield break
** statement stops iteration **once a condition is met**.
Best Practices for Using Iterators
- Use **
yield return
** when working with large datasets to avoid unnecessary memory allocation. - Use **
yield break
** to stop iteration early based on a condition. - Implement **
IEnumerable
** and **IEnumerable<T>
** when creating custom iterators. - Use iterators with **LINQ** for efficient data processing.
- Avoid modifying collections while iterating over them.