C# IEnumerable and IEnumerator: An In-depth Exploration from Basics to Advanced

Laks Tutor
3 min readAug 15, 2023

--

Introduction

Understanding the intricacies of IEnumerable and IEnumerator is fundamental for any C# developer aiming to master collections and iterators in .NET. These interfaces serve as the backbone of iteration over collections in C#. Let's embark on a journey, starting from the basics to the deeper realms of these essential interfaces.

Basics of IEnumerable and IEnumerator

What are IEnumerable and IEnumerator?

  • IEnumerable: This is an interface that provides a method to retrieve an enumerator for a collection. Any class that implements IEnumerable can be used with a foreach loop.
  • IEnumerator: This interface provides methods to iterate over a collection, allowing forward-only cursor movement through the collection.

Basic Usage:

When you write a foreach loop like this

foreach (var item in collection)
{
Console.WriteLine(item);
}

Under the hood, this loop is translated into a pattern that uses the IEnumerable and IEnumerator interfaces.

Diving Deeper

IEnumerable Interface:

The primary responsibility of IEnumerable is to produce an enumerator. It has just one method:

IEnumerator GetEnumerator();

IEnumerator Interface:

IEnumerator provides the mechanics for iteration with three members:

  • Current: Gets the current item in the collection.
  • MoveNext(): Advances to the next item. Returns false if the end of the collection is reached.
  • Reset(): Resets the enumerator to its initial position.

IEnumerable<T> and IEnumerator<T>:

.NET Framework 2.0 introduced generics, and with it came the generic versions of these interfaces. The generic versions provide type safety and eliminate the need for casting.

Advanced Usage and Concepts

Creating a Custom Enumerable Type:

Suppose you want a custom collection to support foreach. Implement IEnumerable and IEnumerator:

public class SimpleCollection : IEnumerable<int>
{
private int[] data = { 1, 2, 3 };
public IEnumerator<int> GetEnumerator()
{
for (int i = 0; i < data.Length; i++)
{
yield return data[i];
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

The yield keyword here helps to produce items one by one.

Manual Iteration using IEnumerator:

Although foreach provides a convenient way to iterate, you can also use IEnumerator manually:

var numbers = new List<int> { 1, 2, 3 };
IEnumerator<int> enumerator = numbers.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}

Deferred Execution:

When working with LINQ, the queries make extensive use of IEnumerable to provide deferred execution. This means the query doesn't run until you enumerate over its results.

var numbers = new List<int> { 1, 2, 3, 4 };
var evenNumbers = numbers.Where(n => n % 2 == 0);
numbers.Add(6); // Modifying source collection
foreach (var even in evenNumbers) // Query runs here
{
Console.WriteLine(even); // Outputs: 2, 4, 6
}

Considerations and Pitfalls:

  1. State of Iterators: Remember that IEnumerator holds state. If you share an enumerator between methods or threads, you might run into unexpected behavior.
  2. Modification During Iteration: Modifying a collection while iterating through it using an enumerator will throw an exception. Always be cautious of this.
  3. Disposing Enumerators: The generic IEnumerator<T> interface implements IDisposable. It's a good practice to dispose of enumerators once done.

Best Practices:

  1. Prefer foreach Over Manual Iteration: Unless you have a good reason, use foreach for better readability.
  2. Be Wary of Deferred Execution: Always be aware that with LINQ and IEnumerable, the query execution can be deferred.
  3. Dispose Explicitly: If manually iterating, always dispose of the IEnumerator object.

Conclusion

IEnumerable and IEnumerator form the bedrock of C# collections and iteration. While the basics can get you started, truly mastering these interfaces allows for efficient and elegant code, especially when dealing with collections, custom iterators, or LINQ. Understanding their inner workings and nuances not only makes you a better developer but also unravels some of the magic behind the scenes in C#.

--

--

Laks Tutor

Software Architect & .NET expert. Specializing in Docker & Kubernetes. Freelance corporate trainer. Shaping tech & sharing insights on Medium.