DEV Community

Cover image for How to Create Infinite Collections Using IEnumerable Properly
Gabriel Schade
Gabriel Schade

Posted on

How to Create Infinite Collections Using IEnumerable Properly

All C# developers faced these interfaces at some point, but how to use them? And better than that, how to use them properly? — Because I’ve seen a lot of mistakes with these guys.

The main point of writing this article is the fact that I lost the count about how many times I’ve seen mistakes and misunderstoods related to C# collections, so I hope to clarify some points here.

Before we start, let’s go a little back and see the cover image at the beginning of the text. It’s a visualization about how you may thinking about IEnumerables.

It works like a Turing Machine tape with a cursor that start pointing to null. This cursor move only straight forward (to right in the image), without index access and besides that, only the necessary information to iterate the collection is provided by an IEnumerable.

Having said that, we can start to code. Let’s check the IEnumerable implementation (with and without generics):

And that’s all. There’s no one more line code at IEnumerable implementation.

What does this suggest?

IEnumerable actually is a IEnumerator factory. Now we need to check IEnumerator out. It’s a little bit more complex, but we can handle it.

There’s two different interfaces, with and without using generics, just like IEnumerable.

The IEnumerator is the one who provides the information about how to iterate a collection (and IEnumerable that is the famous one, how unfair is that?).

In fact, when we use the foreach loop, C# internally calls the GetEnumerator of the collection we’ll iterate and at each step it calls the MoveNext method to move the cursor forward.

Let’s code a super simple code to iterate an IEnumerable of integers using a foreach loop:

It’s pretty simple, isn’t?

As I said before, this code is a simple syntax sugar to another code a little bit more complex, but still a simple code snippet:

This code is a lot more uglier but it does the exactly same thing. The first step got the enumerator using GetEnumerator method, after that, we can use the MoveNext method to iterate each of IEnumerable elements.

It’s interesting to notice that the MoveNext method is called even before we got the first element. It occurs because the enumerator cursor start pointing to one position before the first element (as shown in the tape image).

The MoveNext method have a design that I particularly don’t like. It does two different things.

  1. One of these things is to move the cursor to the next position, which is the main purpose;
  2. The secondary thing is what this method returns. It returns true if the cursor is pointing to a valid position after it was moved or it will return false if isn’t.

My problem with the design of this method is the fact that the main operation, move the cursor to the next element, is caused only by a side effect, but this is a topic for another article, let’s move on.

After call the MoveNext method the first time, we’ll move the cursor to the very first position of the IEnumerable, like the image below:

First Position

And the property Current just returns the value at the position that the cursor points to.

Having said that, how about to create a brand new collection containing all integer positive numbers that exists?

Yeah, you read it correctly, a collection with all numbers, which means, a infinity collection.

Here’s a thing before we start to code, the whole point of this implementation is see how IEnumerator and IEnumerable works under the hood with a foreach loop, so, don’t take it as the best implementation possible for a new collection, it’s just an experiment, right?

Let’s start with an IEnumerator, so, just create a new class that implements IEnumerator<int>, It will looks like the code below:

So, now we need to create our own stuff now. In order to create an infinite collection, we’ll use the cursor itself as a value.

Let’s create a new field called _current which starts at -1 and will be incremented as the MoveNext method is called (usually the value is stored at the IEnumerable, but this isn’t a regular example, remember?)

Ok, but let’s understand why _current starts with -1 instead of zero. The answer is pretty simple, it’s because the MoveNext method is called before the iteration.

Now, let’s go to MoveNext method, you probably already know what to do here. We need to increase the _current value and always return true, after all, it’s an infinite collection, so always is possible to move to the next one.

We don’t need to worry about the Dispose method now, so let’s implement the Reset method by reseting the _current to its initial value.

Now, let’s implement our collection itself. It’ll be easy, trust me. All we need is implement the IEnumerable<int> interface and return an instance of our IEnumerator.

Maybe for some reason, you may need return new instances any time you call GetEnumerator, but for our example, only one instance is enough.

Now we can use our own class inside of a foreach loop:

And we can get the next, the next, and the next and keep doing that forever.

Infinite Collection

How cool is that?

So, everything was implemented correctly, right? — Not exactly.

Let’s force an interruption by using break:

BANG! — An exception was thrown.

Why this exception was thrown? — Simple, the Dispose method wasn’t implemented yet.

Right, but when it’s called?

Just after the loop! In order to remember, let’s reimplement it without foreach sugar syntax, in other words, by using while loop:

Now the things are more clear, aren’t they?

When we iterate across an IEnumerable we use the using keyword, and as you probably already know, the Dispose method is called at the end of the using scope.

The reason why the Dispose method is called is a lot more clear with this syntax, even though it looks worse. We can fix it just by calling Reset method at Dispose.

Warning

This isn’t the best way to implement the Dispose method whatsoever, this is just an experiment, ok?

Now, you have your own infinite collection, it’s time to snapping your fingers (Like Thanos did)!

See you in the next post!

Top comments (0)