Introduction
The foreach
loop in C# provides a simple, clean way to iterate over collections. To make a custom class compatible with the foreach
loop, the class needs to implement the IEnumerable
interface.
This article explores how to enable foreach
functionality in a custom C# class.
Implementing IEnumerable
The IEnumerable
interface requires that your class implements the GetEnumerator
method, which returns an IEnumerator
. The IEnumerator
iterates over the collection, maintaining the state of the iteration.
Basic Implementation Steps
- Implementing
IEnumerable
:- Add
IEnumerable
to your class. - Implement the
GetEnumerator
method.
- Add
- Creating an Enumerator:
- You can either return the enumerator of an internal collection or implement a custom enumerator.
Example: Custom Collection Class
Here’s an example of a custom collection class that implements IEnumerable
:
public class CustomCollection<T> : IEnumerable<T>
{
private readonly List<T> _items = new List<T>();
public void Add(T item)
{
_items.Add(item);
}
public IEnumerator<T> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
In this example, CustomCollection<T>
is a generic collection class that stores its elements in a List<T>
. By implementing IEnumerable<T>
, it can be used with a foreach
loop.
Usage with Foreach
You can now iterate over instances of CustomCollection<T>
using a foreach
loop:
var collection = new CustomCollection<string>();
collection.Add("Item 1");
collection.Add("Item 2");
foreach (var item in collection)
{
Console.WriteLine(item);
}
Advanced Implementation: Custom Enumerator
In some cases, you might need a custom enumerator. This is particularly useful when the collection structure is not based on existing .NET collection types.
public class CustomCollection<T> : IEnumerable<T>
{
// ... other members ...
publicIEnumerator<T> GetEnumerator()
{
for (int i = 0; i < _items.Count; i++)
{
// Custom logic for yielding items
yield return _items[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Best Practices
- Thread Safety: Be aware of thread safety issues if the collection can be accessed by multiple threads.
- Performance Considerations: For large collections, consider the performance implications of your enumerator logic.
- Consistency: Ensure that the state of the collection remains consistent during enumeration.
Conclusion
Enabling foreach
functionality in a custom C# class involves implementing the IEnumerable
(or IEnumerable<T>
) interface and providing an appropriate enumerator.
This not only allows your class to be used with the foreach
loop but also makes it compatible with many other features of the .NET framework that work with collections.
Whether you use an enumerator of an internal collection or implement a custom enumerator, the key is to provide a mechanism for iterating over the elements of your class in a sequential manner.