Foreach, IEnumerable and IEnumerator in C#

Highlighted image - laptop and monitors with code at them

Today, we’re taking a deeper look at foreach loop in C#. What does a collection need to be able to use it in a foreach loop? Does it have to implement IEnumerable interface? These questions are often asked during interviews, so it’s worth knowing the answers ?

We will go through a step-by-step example in building our own custom collection to see how all that works. Let’s dive in! ?

Throughout this article, I’m working with a Unit Tests project using .NET 5, C# 9.0 and NUnit. It makes it easier to play with the code on your own. We can create our custom collection and at the same time try it out in a foreach loop in a test method. I recommend this approach for testing out various programming concepts for yourself ?

Custom collection implementing IEnumerable<T>

First, we want to implement our own, custom collection in C#. The most obvious solution is to implement IEnumerable<T> interface. Our IDE will require our class to implement IEnumerator GetEnumerator() and IEnumerator IEnumerable.GetEnumerator() methods, so let’s do that:

Of course, this is just an example to satisfy the foreach loop, so we won’t care about the actual implementation of these methods ?

Custom collection implemented in such a way can be used in foreach loop:

Custom collection used in a foreach loop (C#)

Does foreach require IEnumerable?

Let’s try to get rid of implementing IEnumerable interface. As soon as we do it, our IDE complains:

Custom collection not implement IEnumerable and IDE complaining about "IEnumerable.GetEnumerator" method

Let’s try to remove IEnumerable.GetEnumerator() method completely, so our custom collection looks as follows:

Now guess what – we can still use MyCollection within the foreach loop!

Custom collection used in a foreach loop (C#)

So you already know that, when asked during an interview whether foreach needs a collection to implement IEnumerable, the answer is no ?

Custom IEnumerator

Currently, our collection has a single GetEnumerator() method returning IEnumerator<MyObject>. We already know that this method is needed in a collection to be able to use it within a foreach loop.

However, let’s work on what this method returns. We’ll implement our custom IEnumerator. Again – the most obvious solution is to create a class implementing IEnumerator<T> interface:

That’s the implementation proposed by the IDE (Rider). We can now change our collection to use this custom enumerator. See that it can still be used within foreach:

Custom collection (without implementing any interface) returns a custom enumerator MyObjectEnumerator

So far, so good. But why all these methods in MyObjectEnumerator? ?

Does foreach need an enumerator implementing IEnumerator?

If we remove inheritance from IEnumerator from MyObjectEnumerator, the IDE only complains about IEnumerator.Current property, so let’s get rid of it. Our custom enumerator now looks as follows:

Yeah, you guessed it again – we can still use our collection in a foreach loop ?

Custom collection used in a foreach loop (C#)

However… Does our custom enumerator really needs all of these stuff: MoveNext(), Reset(), Dispose() and MyObject Current ? Let’s remove all of them and see what our IDE tells us:

IDE (JetBrains Rider) error:
Type 'ForeachFun.MyCollection' cannot be used in 'foreach' statement because it neither implements 'IEnumerable' or 'IEnumerable', nor has suitable 'GetEnumerator' method which return type has 'Current' property and 'MoveNext' method

That’s the error from IDE when trying to iterate through our custom collection in foreach:

Type ‘ForeachFun.MyCollection’ cannot be used in ‘foreach’ statement because it neither implements ‘IEnumerable’ or ‘IEnumerable’, nor has suitable ‘GetEnumerator’ method which return type has ‘Current’ property and ‘MoveNext’ method

This error actually tells us everything. This is the ultimate answer to the legendary C# interview question: “What does a collection need to be able to use it in foreach loop?”. In other words: “Is it necessary for a collection to implement IEnumerable to use it in a foreach loop?”

The answer is: a collection needs to have a GetEnumerator() method returning an object of type having Current property and bool MoveNext() method. No interfaces are required anywhere here ?

The compiler uses duck typing to find these two necessary ingredients of the type returned from GetEnumerator(). It means that is looks for these properties by text. Later, depending on the type of Current property, a single element inside the foreach is typed accordingly. Only if this duck searching fails, the compiler checks whether the collection implements the interfaces.

In the end, this is our simplest and fully legit code (except the actual implementations of the methods, which is out of scope of this article):

Summary

I hope you got to know something new about foreach loop from this article. This may not sound like a knowledge you’d need on a daily basis, but it’s worth knowing how stuff works under the hood ? Plus, you can always score a point during your next interview ?!

5 2 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x