IEnumerator.Current property and IEnumerator.MoveNext method
Here’s a question: What happens to the Current property of an IEnumerator before and after the MoveNext() call? When I say ‘after the MoveNext() call’, I mean after MoveNext() returns a false indicating an end of the collection.
I was going through the MSDN for IEnumerator.Current and the first paragraph basically boils down to: If MoveNext() method has never been called on an IEnumerator, the Current property is undefined. I wanted to know what ‘undefined’ means – is it null? If so, what if the IEnumerator is a collection of value types – say, a collection of integers. Will that return a null value as well?
I have two methods – one returning an IEnumerator of a class Product (the same class used in my previous blog) and another of the type ‘int’.
1: private static IEnumerator<Product> GetEnumerableProducts()
2: {
3: for (int i = 0; i < 5; i++)
4: {
5: yield return new Product
6: {
7: Id = i,
8: Name = string.Format("Name-{0}", i)
9: };
10: }
11: }
12:
13: private static IEnumerator<int> GetEnumerableInts()
14: {
15: for (int i = 0; i < 5; i++)
16: {
17: yield return i;
18: }
19: }
In my calling code, I have:
1: private static void BehaviorOfIenumerator()
2: {
3: IEnumerator<Product> products = GetEnumerableProducts();
4: IEnumerator<int> ints = GetEnumerableInts();
5:
6: Console.WriteLine("before calling MoveNext()");
7: Console.WriteLine(products.Current == null ? "null" : products.Current.Name);
8: Console.WriteLine(ints.Current);
9: }
The output is:
This is interesting!
Lesson 1: The Current property of an IEnumerator returns the default value of the type it contains – null for reference types and 0 for value type (specifically ‘int’ in our case) before the MoveNext() has been called for the first time.
Moving on, to know what happens to the Current property after the MoveNext() returns false. In other words, what value does the Current property have after the collection has been iterated? According to MSDN:
Current also throws an exception if the last call to MoveNext returned false, which indicates the end of the collection.
At first glance, the phrase - ‘throws an exception’, sounds very vague. They don’t specify what exact exception gets thrown. I modified my calling method as:
1: private static void BehaviorOfIenumerator()
2: {
3: IEnumerator<Product> products = GetEnumerableProducts();
4: IEnumerator<int> ints = GetEnumerableInts();
5:
6: Console.WriteLine("before calling MoveNext()");
7: Console.WriteLine(products.Current == null ? "null" : products.Current.Name);
8: Console.WriteLine(ints.Current);
9:
10: Console.WriteLine("products collection");
11: while (products.MoveNext())
12: {
13: Console.WriteLine(products.Current.Name);
14: }
15:
16: Console.WriteLine("ints collection");
17: while (ints.MoveNext())
18: {
19: Console.WriteLine(ints.Current);
20: }
21:
22: Console.WriteLine("after iterating through the collections");
23: Console.WriteLine(products.Current.Name);
24: Console.WriteLine(ints.Current);
25: }
So I’m calling the MoveNext() methods for the two collections in line 11 and 17. Let’s see the output and I’m particularly interested in line 23 and 24.
Again… This is interesting! Not only was an exception not thrown, the Current property actually contained a non-null, non-zero value.
Lesson 2: After the iteration is complete (MoveNext() returns false), the Current property will hold the value of the last item of the collection.