Implementing IEnumerable and IEnumerator in C#
There are many times when you are writing code where you do things like this:
Where in this case people is some kind of collection object - an array, ArrayList, generic List etc.
This foreach facility is very useful and used a lot of the time. So what do you need to do if you are writing your own collection classes and want client code to be able to iterate over them using foreach? Well this is all to do with behaviour and so it is no surprise that the solution to this problem lies with interfaces.
The interfaces which we need to use to achive this are IEnumerable and IEnumerator.
So lets say we have a class to represent a person as follows:
And lets say we have a custom class which represents a collection of people as follows:
Note that if we used an existing collection class such as a generic list then we would already have a class which we are able to iterate over using a foreach statement. What I mean by this is if we simply subclassed an existing collections class - in this case though we have an existing collections class (ArrayList) as a member of our class. This article is about custom classes and what we need to do to enable the foreach behaviour and in fact once you learn how this is done you will see that this is how other intrinsic classes do it anyway.
So the first thing we need to do is make our People class implement the IEnumerable interface. We do this of course as follows:
Note that this interface is in the System.Collections namespace so you will need to put using System.Collections at the top of your class.
If you look at the definition for IEnumerable you will see it has just 1 method - GetEnumertor. You can right click on the Interface name in your class and click on implement interface and Visual Studio will kindly fill in some skeleton code so that your class implements the interface and will compile.
So clicking on implement interface as above will give you the following code:
Now we can see by looking at the signature for GetEnumerator that the object this method needs to return is one which implements the IEnumerator interface. Therefore we can see that IEnumerable and IEnumerator are very closeley tied together.
Lets have a look at this interface. If you right click on it in Visual Studio (in the method Visual Studio just added for us) and click on Goto definition you will see the following:
So we can see that there is some COM stuff which we can ignore as that is not important for what we are looking at. Other than that though there are two methods and one property. The Current property returns the current object we are pointing at. This will be used in the foreach statement to get the current object. Note that this returns an object and so supports any class at all. The foreach statement under the hood will be doing some casting to your specific object. Then we have a MoveNext method which advances the object we are pointing at by 1. This is typically done by having some kind of field called something like index maybe which starts at -1 and then is advanced 1 value at a time and is used to retrieve the current object by things like peopleList[index].
So MoveNext will advance this index and return a boolean which is true if the advancement was ok or false if we have reached the end of the collection. And so when false is returned, then the foreach statement will know to finish.
Finally we have a Reset method which should just set our Index back to -1.
Ok so we have 3 options for getting our hands on an IEnumerator object. These are firstly to use one which our collection class provides. In our example we have a custom class called People but under the hood that just stores its data in an ArrayList. ArrayLists already implement IEnumerable and so have a GetEnumerator method we could use as follows:
We can easily test this by running the following console application:
And this should work fine giving us the following results:
Our second option for getting our hands on an Enumerator is to write one ourselves. Now of course this is pointless in our current scenario but it is useful to be able to do this for times when you have to or want to for various reasons. Also someone had to write the GetEnumerator method we just borrowed and that might be your job one day!
So if you are simply wrapping an existing collection object with your class then in practical terms you should just use the GetEnumerator method of that.
We should look at creating our own class which implements IEnumerator though just in case we ever do need to for whatever reason.
So the way I see it is we can either create a brand new class which implements IEnumerator or we could actually make the class we already have implement IEnumerator which is fine since .net allows multiple inheritance of interfaces.
Lets look at creating a new class first and the way the interfaces are defined does suggest that this is the way we are intended to implement this solution otherwise the two interaces could be wrapped up into one. Its is good to seperate the responsibilities like this as this is good OO design but also allows us to create different iterators to meet different needs as well as creating one iterator to fulfill the needs of multiple IEnumerable classes. However it is possible to wrap both classes into one so we will also look at this afterwards.
So first we create a class called PeopleEnumerator as follows:
So we have stated that we want this class to implement IEnumerator and also coded in an ArrayList called peopleList. This is passed in via the constructor whenever we create an instance of this class and this will be the ArrayList reference in our People class. We have also coded in an int variable caled index which will keep track of which object in the collection we are pointing at.
Ok so this won't compile yet as we haven't implemented the IEnumerator interface yet so let's do that. Right click on the IEnumerator and click on implement interface and then Visual Studio will kindly fill in the skeleton requirements needed to fulfill this interface. You can then and fill in the blanks.
The resulting code after doing this will then need to look like this:
So we have 1 public property and 2 methods in our interface. The Current property returns the current instance of the collection we are pointing at - this uses the value of index. The MoveNext method simply increments the index value by 1 and returns true if it was able to do so or false if we are at the end of the collection. Finally Reset will set the index value back to -1.
These methods and properties will be used when we use a foreach statement. When a foreach statement is compiled then this is when the magic will happen and the simple foreach statement will be replaced with method and property calls.
You can also write your own code to iterate over such a collection and directly use the methods in the interface but no need to do that then we have the useful and easy foreach statement.
If you have written code in the way we have done above then it may be worth considering making your iterator class a nested class. This is for organizational purposes and possibly also for the purpose of hiding class acessibility - after all you don't want people creating instances of you iterator themselves - you always want this to through the GetEnumerator method.
In this case then the full thing would look like this:
Now that you see how an object should work when it implements IIterator then you should be able to see how easy it would be to combine these classes into one should that be your wish.
You would simply need to make your People class implement IEnumerator as well as IEnumerable and then make your class implement the Current property and the MoveNext and Reset methods. There would then of course be no need to pass in any refernces to the collection as you would be working in that class anyway.
So that's about it. Any comments or corrections always welcome via the form below.