Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I use IEnumerator for looping in c#?

Tags:

I was wondering if there are any times where it's advantageous to use an IEnumerator over a foreach loop for iterating through a collection? For example, is there any time where it would be better to use either of the following code samples over the other?

IEnumerator<MyClass> classesEnum = myClasses.GetEnumerator(); while(classesEnum.MoveNext())     Console.WriteLine(classesEnum.Current); 

instead of

foreach (var class in myClasses)     Console.WriteLine(class); 
like image 612
lomaxx Avatar asked Jan 19 '09 03:01

lomaxx


People also ask

What does IEnumerator mean?

IEnumerator is an interface, which when implemented allows you to iterate through the list of controls. To implement it requires that you provide two methods - Reset to go back to the beginning of the list, and MoveNext to move forward, and Current to get the current item.

What is iterator in unity?

[…] in Unity are based on C# iterators, which have been covered in the first part of this tutorial: Iterators in C#: yield, IEnumerable and IEnumerator. Iterators are an expressive way to model objects that can be iterated upon, such as lists and […] .NET. c#


2 Answers

First, note that one big difference in your example (between foreach and GetEnumerator) is that foreach guarantees to call Dispose() on the iterator if the iterator is IDisposable. This is important for many iterators (which might be consuming an external data feed, for example).

Actually, there are cases where foreach isn't as helpful as we'd like.

First, there is the "first item" case discussed here (foreach / detecting first iteration).

But more; if you try writing the missing Zip method for stitching two enumerable sequences together (or the SequenceEqual method), you find that you can' use foreach on both sequences, since that would perform a cross-join. You need to use the iterator directly for one of them:

static IEnumerable<T> Zip<T>(this IEnumerable<T> left,     IEnumerable<T> right) {     using (var iter = right.GetEnumerator())     {         // consume everything in the first sequence         foreach (var item in left)         {             yield return item;              // and add an item from the second sequnce each time (if we can)             if (iter.MoveNext())             {                 yield return iter.Current;             }         }         // any remaining items in the second sequence         while (iter.MoveNext())         {             yield return iter.Current;         }                     }             }  static bool SequenceEqual<T>(this IEnumerable<T> left,     IEnumerable<T> right) {     var comparer = EqualityComparer<T>.Default;      using (var iter = right.GetEnumerator())     {         foreach (var item in left)         {             if (!iter.MoveNext()) return false; // first is longer             if (!comparer.Equals(item, iter.Current))                 return false; // item different         }         if (iter.MoveNext()) return false; // second is longer     }     return true; // same length, all equal             } 
like image 52
Marc Gravell Avatar answered Sep 21 '22 16:09

Marc Gravell


According to the C# language spec:

A foreach statement of the form

foreach (V v in x) embedded-statement 

is then expanded to:

{     E e = ((C)(x)).GetEnumerator();     try {             V v;             while (e.MoveNext()) {                     v = (V)(T)e.Current;                     embedded-statement             }     }     finally {             ... // Dispose e     } } 

The essense of your two examples are the same, but there are some important differences, most notably the try/finally.

like image 20
Jay Bazuzi Avatar answered Sep 22 '22 16:09

Jay Bazuzi