Skip to content

Custom Foreach Example Using IEnumerator and IEnumerable

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:

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:

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
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.

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:

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.

3.2 GetStoreName Member

The GetStoreName member function returns the store name of the Store instance. The code is below:

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
Variable Number of Parameters to Constructor

The code is below for copy & paste:

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.

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:

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

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.

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:

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.

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:

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.

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.

The For each Loop invokes our IEnumerable and IEnumerator function in the following order:

  1. 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.
  2. 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
Custom ForEach Example Output

Source Code: Download

Advertisements

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: