2

I was looking into the IEnumerable and trying the example given in this link. I understand that when we iterate using foreach the GetEnumerator() method gets call because my List class has implemented IEnumerable (or may be I am wrong).

   public class List<T> : IEnumerable
    {
        private T[] _collection;
        public List(T[] inputs)
        {
            _collection = new T[inputs.Length];
            for (int i = 0; i < inputs.Length; i++)
            {
                _collection[i] = inputs[i];
            }
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return (IEnumerator)GetEnumerator();
        }
        public CollectionEnum<T> GetEnumerator()
        {
            return new CollectionEnum<T>(_collection);
        }
    }

public class CollectionEnum<T> : IEnumerator
    {
        public T[] _collection ;
        int position = -1;
        public CollectionEnum(T[] list)
        {
            _collection = list;
        }
        public bool MoveNext()
        {
            position++;
            return (position < _collection.Length);
        }
        //implementation on Current and Reset
    }

Then, it is also mentioned that implementation of IEnumerable is not required to iterate using foreach. So, in the above code if I remove the implementation of IEnumerable the foreach must work. So my List<> class looks like

public class List<T>
{
    private T[] _collection;
    public List(T[] persons)
    {
        _collection = new T[persons.Length];
        for (int i = 0; i < persons.Length; i++)
        {
            _collection[i] = persons[i];
        }
    }
    public CollectionEnum<T> GetEnumerator()
    {
        return new CollectionEnum<T>(_collection);
    }
}

And which does work. Now I did not understand how foreach knows my class has a method call GetEnumerator() which returns a IEnumerator type.

Rahul Chakrabarty
  • 2,149
  • 7
  • 39
  • 70
  • 3
    `foreach` knows nothing, it's just language grammar. The C# *compiler* knows how to generate CIL for the statement, and its implemented to look for a `GetEnumerator` method that returns an `IEnumerator`. – Preston Guillot Mar 05 '16 at 19:13
  • 1
    Possible duplicate of [How do foreach loops work in C#?](http://stackoverflow.com/questions/398982/how-do-foreach-loops-work-in-c) – George Vovos Mar 05 '16 at 19:40
  • @Nkosi's answer corrects my previous comment - the type returned from `GetEnumerator` *doesn't* need to implement `IEnumerator`, but it *does* need to provide members that match the ones defined in that interface. – Preston Guillot Mar 05 '16 at 19:58

2 Answers2

2

The article you linked to provided the explanation to you already in the remarks.

If your collection does not implement IEnumerable, you must still follow the iterator pattern to support this syntax by providing a GetEnumerator method that returns an interface, class or struct....that contains a Current property, and MoveNext and Reset methods as described by IEnumerator, but the class does not have to implement IEnumerator.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
1

As Nkosi mentions, in interpreting foreach, the compiler looks for a pattern originally represented in IEnumerable and IEnumerator.

Earlier versions of the C# compiler required the implementation of these interfaces. However, with the advent of LINQ, the language and compiler have been adjusted to do more of recognizing patterns.

For instance, you can create a LINQ query around an object that has a Where method but doesn't implement IEnumerable.

Similarly, you can await any object that follows the Awaitable Pattern not just Task or Task.

Once you understand the particular methods the compiler is looking for to satisfy a pattern it becomes easier to wrap your head around why IEnumerable is not required for foreach. Remember also that foreach is really just syntactic sugar for traversing a collection of objects.

Eniola
  • 710
  • 1
  • 7
  • 23