Today in this section, we'll see IEnumerable<T> in action and will see how it actually works and holds true for all collections. As I already said in one of my articles that collections don't iterate themself, they need enumerators to loop through them and its IEnumerable<T>'s job to provide the enumerators. So whenever we loop through any collection using foreach(), we are actually invoking IEnumarable<T> to get the enumerator. So, IEnumerable<T> exposes only one method and that is GetEnumerators().
Here, enumerator uses three basic properties to iterate in the list and that is MoveNext(), Reset and Current. MoveNext() will iterate until the collection ends and Current will set the subsequent item to the current one. Now, let's see that in action.
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Linq;
- using System;
-
- namespace Collections
- {
- internal class Stack
- {
- private static void Main(string[] args)
- {
- string[] monthsofYear =
- {
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December"
- };
-
- ShowItems(monthsofYear);
- Console.ReadLine();
- }
-
- public static void ShowItems<T>(IEnumerable<T> coll)
- {
-
-
- using (IEnumerator<T> enumerator = coll.GetEnumerator())
- {
- bool nextItem = enumerator.MoveNext();
-
- while (nextItem)
- {
- T item = enumerator.Current;
- Console.WriteLine(item);
- nextItem = enumerator.MoveNext();
- }
- }
- }
- }
-
-
- }
Now, consider the scenario of foreach(). As shown below in the example foreach() is pretty straightforward, I could have used it in the Main method directly as I was using in the previous examples. However, I just wanted to emphasize the one point that foreach() internally replaces the code with with the previous example of IEnumerator<T>.
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Linq;
- using System;
-
- namespace Collections
- {
- internal class Stack
- {
- private static void Main(string[] args)
- {
- string[] monthsofYear =
- {
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December"
- };
-
-
- ShowItems2(monthsofYear);
- Console.ReadLine();
- }
-
- public static void ShowItems<T>(IEnumerable<T> coll)
- {
-
-
- using (IEnumerator<T> enumerator = coll.GetEnumerator())
- {
- bool nextItem = enumerator.MoveNext();
-
- while (nextItem)
- {
- T item = enumerator.Current;
- Console.WriteLine(item);
- nextItem = enumerator.MoveNext();
- }
- }
- }
-
- public static void ShowItems2<T>(IEnumerable<T> coll)
- {
- foreach (T item in coll)
- {
- Console.WriteLine(item);
- }
- }
- }
-
-
- }
And of course the result will be the same only.
Now, there is one exception to this; if the compiler notices that the collection we are iterating through is an Array then it will simply convert the foreach() method to a for loop than IEnumeartor<T> implementation, since that is the most efficient way of iterating. But, this only holds for arrays.
One more point is, enumeration is a read-only operation, so if you try to modify the collection on the fly and iterate through it, this won't allow that.
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Linq;
- using System;
-
- namespace Collections
- {
- internal class Stack
- {
- private static void Main(string[] args)
- {
- var monthsofYear = new List<string>
- {
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December"
- };
-
-
- foreach (var item in monthsofYear)
- {
- monthsofYear[2] = "Financial Month";
- Console.WriteLine(item);
- }
- Console.ReadLine();
- }
-
-
- }
-
-
- }
However, the preceding restriction is not applicable for all the collections. For example, if I change it to an Array and run it again then the compiler won't complain it. However, one point to note is that it's not a good practice to modify the element while iterating and the reason for this is foreach() for arrays is converted into a for loop, hence the modification is allowed in that.
Thanks for joining me.
Rahul sahay,
Happy Coding