1. About Foreach Iterations
In this example, we will see the usage of IEnumerator and IEnumerable interfaces to bring up the custom foreach loop for user-created collection class. Before we move on let us see how a classic for loop and a modern foreach loop works. First, we will start with ‘for loop’.
When we iterate the collection through any loop, we pay caution to the Upper-Bound of the collection. For example, consider the below code:
1 2 3 4 5 6 7 8 9 10 |
//Sample 01: An Example Loop Iteration int[] array = new int[4]; array[0] = 1; array[1] = 2; array[2] = 3; array[3] = 4; Console.WriteLine("Iterating using Standard " + "for loop"); for (int i = 0; i < 4; i++) Console.WriteLine(array[i]); |
Here, we formed an array which comprises Four integer numbers in it. Here, the Upper-Bound of the array is 3. When we are iterating through the array, we should make sure our iteration should not go beyond this limit to avoid Run-Time errors. The condition in the For Loop (I < 4) will ensure this Upper-Bound check. Let us look at the ForEach Loop which is iterating the same array. The code is below:
1 2 3 4 5 |
//Sample 02: Loop Iteration with ForEach Console.WriteLine("Iterating using " + "foreach loop"); foreach (int number in array) Console.WriteLine(number); |
In the above code, the foreach loop takes care of Upper-Bound check. We no need to worry about it. The output of this code is below:

For Loop and ForEach Loop – Output
In this article, we will create a Class called Book and Store. The Store Class will maintain Books collection in it. In the Store Class we will provide “foreach loop” iteration support. This will allow the user to iterate Store for each Book it contains. To put it differently, it is a custom foreach loop iteration for store class.
The youtube video below explains the need for custom foreach and example we create here:
2. The Book Class
We define the Book Class in a C-Sharp file called Book.cs. In the Class, we also define member variables which will store the ISBN and Book name. A constructor is needed to load these member variables. We also override the ToString Function so that our Class knows how to display the instance as a string.
The Store Class which we will write in the next section holds multiple objects of this Book Class as a collection. Note, we apply IEnumerator to iterate through the instances this book class. Below is the code for the Book Class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
namespace CustomForEach { //Sample 03: Book Class public class Book { private int isbn; private string book_name; public Book(int pisbn, string bname) { isbn = pisbn; book_name = bname; } public override string ToString() { return book_name + " (" + isbn.ToString() + ")"; } } } |
3. IEnumerable Store Class
3.1 Store With Array of Books
We define the store Class in a C# file named as ‘store.cs’. Also, we sign for IEnumerable contract for this Class and this informs the client (Code which uses this Class) that it has support of ForEach iteration. At line 4, we declare a String member variable to keep the name of the store. Index member variable at line 5 to maintains the iteration index of the “ForEach” loop. At line 6, we define the array of Book which we described in the preceding section. We call this member variable as Books or Books collection. Since this is private, one cannot access it through the instance of the store. But, through the ForEach loop they can iterate through the collection of each Books.
1 2 3 4 5 6 |
public class Store : IEnumerable { //Sample 04: Store has Array of Books private string Store_Name; private int index = 0; private Book[] Books; |
3.2 GetStoreName Member
The GetStoreName member function returns the store name of the Store instance. The code is below:
1 2 3 4 5 |
//Sample 05: Return the Store Name public string GetStoreName() { return Store_Name; } |
3.3 Books as Param Array
The constructor of our Store class initializes the Store Name member and the Books array member. In the second argument we may notice the keyword params (shown in Yellow) which we used to say, constructor can receive a variable number of Book parameter. The first parameter is always the Store name, and it is mandatory. The constructor can take Variable Number Of Parameters from its second argument because of Books array as param in the second argument. For Example, in the picture below, we can see construction of two objects one with two Book arguments and another one with three Book arguments. Note, here we are referring b1, b2 and b3 as Book instances. Inside the constructor, the param array
Bookscol
is iterated to initialize the Books array. Note, the IEnumerator which we will implement soon will iterate through this array.

Variable Number of Parameters to Constructor
The code is below for copy & paste:
1 2 3 4 5 6 7 8 9 10 11 12 |
//Sample 06: Initialize StoreName and Array of Books public Store(string StoreName, params Book[] Bookscol) { Store_Name = StoreName; //6.1 Set Array Size Books = new Book[Bookscol.Length]; //6.2 Iterate through Variable Number of Params for (int x = 0; x < Bookscol.Length; x++) Books[x] = Bookscol[x]; } |
Now you can watch youtube demo which creates Book and Store classes:
3.4 IEnumerable Contract
Since our class implements IEnumerable, we provide the implementation for its contract. The
GetEnumerator
function fulfills this contract. This function should return an
IEnumerator
object. The
IEnumerable
interface tells that our store class gave support to ForEach. Besides, the IEnumerator contract states how the items of the book array can be iterated. The below code returns a class object of type
BookIterator
which we will define as Inner Class in the next section of this article.
1 2 3 4 5 |
//Sample 08: Implement GetEnumarator of IEnumerable public IEnumerator GetEnumerator() { return new BookIterator(this); } |
4. The BookIterator Class With IEnumerator
In the previous section, we saw the GetEnumerator Function returns instance of BookIterator. But, this Function’s return type is IEnumerator. Hence, the BookIterator Class implements the IEnumerator (Line 2). Note, the BookIterator is an Inner Class for the Store which implements the IEnumerable interface.
We declare two private members in our Inner Class. The Store member holds the outer class instance and the
Iterator_Index
(Line 8) member variable member retrieves the Book from the Books collection of the outer class. In the constructor (Line 11 through 14), we take Store Instance and copy that to the internal member. We will use this internal member and the
Iterator_Index
to perform the ForEach iteration on the Books collection. The code is below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//Sample 07: Book Iterator - Inner Class private class BookIterator: IEnumerator { //7.1 Hold the reference to perform foreach private Store store; //7.2 Current index on the Books array private int Iterator_Index = -1; //7.3 Hold the reference to the Outer class Instance public BookIterator(Store store) { this.store = store; } |
4.1 IEnumerator Property – Current
The Property Current of the
IEnumerator
, fetches the Book from Books collection from the current position of the
Iterator_Index
(Line 6). The ForEach loop made by the client code make use of this Property on each iteration. Now, the ForEach loop of the client code can retrieve the Book from the Books collection. The property is written as Read Only. Code is below
1 2 3 4 5 6 7 8 |
//7.4 Implement Property Current of IEnumerator public object Current { get { return store.Books[Iterator_Index]; } } |
4.2 MoveNext Function of IEnumerator
We write the “
MoveNext
Function” to move up our iteration pointer to the next element in the books array. Here, we are raising our internal iteration index (Line 5) by 1. Recall, the “Current Property” of the
IEnumerator
gets the element from the collection based on this index location. This
MoveNext
function allows iteration of the elements in the collection.
We also perform the Upper-Bounds check (Line 6) and return true or false. This sets the loop exit criteria for the “ForEach” which will be written by the client of our Store class.
1 2 3 4 5 6 7 8 9 10 |
//7.5 IEnumerator Contract MoveNext. //Return false to state MoveNext not possible public bool MoveNext() { Iterator_Index++; if (Iterator_Index < store.Books.Length) return true; else return false; } |
4.3 Reset Function of IEnumerator
In the
Reset
Method, at line 5, we set the internal iterator index to -1. This function is not needed by the “ForEach” loop. According to Microsoft Details, this method is used in case of COM Interoperability. Below is the implementation:
1 2 3 4 5 6 |
//7.6 IEnumerator Contract Reset //Reset Index to -1 public void Reset() { Iterator_Index = -1; } |
5. Custom Foreach Through BookIterator & IEnumerator
5.1 Setup Books and Stores
In the Program Entry (Main Function), First we create an array of integers and print the values in the Console Window using ForEach loop. This ForEach support on the Standard Array is given by C# Dot.Net Framework itself.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//Sample 01: An Example Loop Iteration int[] array = new int[4]; array[0] = 1; array[1] = 2; array[2] = 3; array[3] = 4; Console.WriteLine("Iterating using Standard " + "for loop"); for (int i = 0; i < 4; i++) Console.WriteLine(array[i]); //Sample 02: Loop Iteration with ForEach Console.WriteLine("Iterating using Standard " + "for loop"); foreach (int number in array) Console.WriteLine(number); |
The above code explained how a ForEach loop worked in an Array. Next, we created Seven instances of the Book class and it is not part of any collection at this moment. Below is the code:
1 2 3 4 5 6 7 8 |
//Sample 9.0: Create List of Books Book b1 = new Book(1020, "Book 001"); Book b2 = new Book(1250, "Book 002"); Book b3 = new Book(4320, "Book 003"); Book b4 = new Book(4520, "Book 004"); Book b5 = new Book(4560, "Book 005"); Book b6 = new Book(1720, "Book 006"); Book b7 = new Book(4335, "Book 007"); |
After the Book objects are ready, we form two book stores and pass the book items to the constructor of the Store Class. Recall, the Store Class constructor uses Parameter Array to collect a variable number of book arguments. At this stage, two Store objects are ready, and they internally have the collection of books held as an array.
1 2 3 4 5 |
//Sample 10.0: Create a Store with List of Books Store AKLBookStore = new Store("AKL Books Store", b1, b2, b3, b4, b5, b6, b7); Store DonaldBookStore = new Store("Donald Robson Store", b3, b4, b7); |
5.2 Use IEnumerator Custom For Loop to Iterate The Books
We make use of the ForEach loop for our Store Collection class and iterate through each book in the store (Line 5-6 and Line 11-12). On each iteration we print the book details and here, we are not worrying about the Upper Bounds as ForEach loop takes care of it.
1 2 3 4 5 6 7 8 9 10 11 12 |
//Sample 11.0: Iterate through Book Store and List Books //11.1: Iterate through First Book Store Console.WriteLine("List of Books in " + AKLBookStore.GetStoreName()); foreach (Book book in AKLBookStore) Console.WriteLine(book.ToString()); //11.2: Iterate through Second Book Store Console.WriteLine("List of Books in " + DonaldBookStore.GetStoreName()); foreach (Book book in DonaldBookStore) Console.WriteLine(book.ToString()); |
The For each Loop invokes our IEnumerable and IEnumerator function in the following order:
- Our custom foreach loop calls the GetEmumerator function. This IEnumarable function gives the BookIterator which implements the IEnumerator and knows how to iterate the Books array. The GetEmumerator function is called only one time for a ForEach loop. It is a kind of Loop initialization.
- For each iteration, Current property is called to retrieve the Book instance and MoveNext is called to advance the iterator to the next book. The sequence is, foreach calls the MoveNext method and then Current Property invokes the book pointed by the BookIterator. Note, the loop exit is decided by the MoveNext function and when it returns false the loop exits.
Below is the output of running the Entire Code:

Custom ForEach Example Output
The below youtube video shows Implementing the IEnumerable and IEnumerator contract:
Source Code: Download
Categories: C#
Tags: GetEnumerator, IEnumerable, IEnumerator, IEnumerator::Current, IEnumerator::MoveNext