blacktea
blacktea

Reputation: 142

Having trouble understanding IEnumerator

I'm currently learing C# for the purpose of effectivly usingRazor and Umbraco, I have a little bit of background in PHP and a reasonable knowledge in JavaScript.

I came across the IEnumerator interface and have had difficulty getting my head around it. I've setup a code snippet below to demonstrate looping through an array with foreach:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace cardEnum
{
    class suitsEnumerator
    {
        private static string[] suits = { "Hearts", "Spades", "Diamonds", "Clubs" };
        public void showAll()
        {
            foreach(string x in suits){
                System.Console.WriteLine(x);
            }
        }
    }
    class run
    {
        static void Main()
        {
            Console.WriteLine("The suits are:");
            var suits = new suitsEnumerator();
            suits.showAll();
            Console.ReadKey();
        }
    }
}

Can someone explain why I would even need to use IEnumerator when I can quite easily loop through the array otherwise. I KNOW this is such a simple question, I just cant think of an reason to use IEnumerable.

Any help at all would be greatly appreciated, thanks!

Upvotes: 3

Views: 360

Answers (7)

Ekk
Ekk

Reputation: 5715

It's good because your code is depend on interface (IEnumerable)

Today type of suits in your code is Array

private static string[] suits = { "Hearts", "Spades", "Diamonds", "Clubs" };

if you decide to use for loop you code look more or less like below

for (int index = 0; index < suits.Length; suits++)
{
    // code here
}

Next year you may have a reason to change its type from Array to List<T>. If you use for you need to update block of code since Array has Length while List has Count property.

Upvotes: 1

Heinzi
Heinzi

Reputation: 172200

This is how the enumerator pattern could be implemented in your example. I hope this clarifies a few things, in particular, the relationship between IEnumerable and IEnumerator:

namespace cardEnum {
    // simple manual enumerator
    class SuitsEnumerator : IEnumerator {
        private int pos = -1;
        private static string[] suits = { "Hearts", "Spades", "Diamonds", "Clubs" };

        public object Current {
            get { return suits[pos]; }
        }

        public bool MoveNext() {
            pos++;
            return (pos < suits.Length);
        }

        public void Reset() {
            pos = -1;
        }
    }

    class Suits : IEnumerable {
        public IEnumerator GetEnumerator() {
            return new SuitsEnumerator();
        }
    }

    class run {
        static void Main() {
            Console.WriteLine("The suits are:");
            var suits = new Suits();
            foreach (var suit in suits) {
                Console.WriteLine(suit);
            }
            Console.ReadKey();
        }
    }
}

Of course, this is a contrived example to aid understanding. Since string[] already implements IEnumerable, there's no reason to reinvent the wheel.


Since C# supports the yields keyword, creating an Enumerator got a little easier recently:

namespace cardEnum {
    // no explicit SuitsEnumerator required
    class Suits : IEnumerable {
        public IEnumerator GetEnumerator() {
            yield return "Hearts";
            yield return "Spades";
            yield return "Diamonds";
            yield return "Clubs";
        }
    }

    class run {
        static void Main() {
            Console.WriteLine("The suits are:");
            var suits = new Suits();
            foreach (var suit in suits) {
                Console.WriteLine(suit);
            }
            Console.ReadKey();
        }
    }
}

Upvotes: 2

Oded
Oded

Reputation: 498904

The C# compiler transforms this:

foreach(string x in suits)

To use IEnumerator (or IEnumerator<T>).

The IEnumerable and IEnumerable<T> interfaces define a GetEnumerator method that returns an IEnumerator (or IEnumerator<T>, respectively) which is what is being used for the iteration you are doing with foreach.

The exception is iteration done with arrays, which the compiler treats differently (thanks @Jon Skeet).

Upvotes: 1

Joshua Marble
Joshua Marble

Reputation: 560

First of all, if you are going to create your own enumerator, you should make the class implement the IEnumerator interface (or its generic equivalent).

public class FooEnumerator : IEnumerator
{
    #region IEnumerator Members

    public object Current
    {
        get { throw new NotImplementedException(); }
    }

    public bool MoveNext()
    {
        throw new NotImplementedException();
    }

    public void Reset()
    {
        throw new NotImplementedException();
    }

    #endregion
}

Typically enumerators are used to move, one item at a time, through a collection. It's a simple interface for supporting the moving items, but not representing the items themselves. It only has the concept of the current item and moving to the next.

IEnumerable, on the other hand, is intended to represent the collection of items. IEnumerable, by its definition, returns an enumerator whose purpose is to enumerate through each item in the IEnumerable collection. They are not mutually exclusive classes, the are dependent classes.

You wouldn't normally create an enumerator to go through your values like in your example. You would create a collection and use an enumerator to navigate it (or at a higher level iterate the collection which uses an enumerator behind the scenes).

Upvotes: 2

Konrad Morawski
Konrad Morawski

Reputation: 8394

You may (and often will) have to to perform some more complex operations than just printing out the values of your objects.

Your class could have to return (yield) objects one by one for some external processing (by some other class, method etc.).

Then exposing an IEnumerator is better than returning an entire collection, because enumerating means you're only passing one object at the time! Not an array of (possibly) one milion elements at once.

Upvotes: 1

IAbstract
IAbstract

Reputation: 19871

Suppose you were to create a custom collection of suits ...learning how to implement the IEnumerable<T> will give you a bit of insight on why it is so useful. Without it, LINQ could not exist as we know it.

Upvotes: 0

Toto
Toto

Reputation: 149

If you look at System.Array you'll see that Array implements IEnumerable. And for each doesn't need an IEnumerable object. It only needs a method called GetEnumerator.

Upvotes: 0

Related Questions