Search code examples
c#genericsienumerablereturn-typeienumerator

How can IEnumerable.GetEnumerator()'s go-to implemetation is to return GetEnumerator(), if GetEnumerator() is of diffrent return type?


I am trying to understand why something like

 class Foo : IEnumerable<int>
    {
        public IEnumerator<int> GetEnumerator()
        {
            //....
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

isn't a compiler error. GetEnumerator() returns IEnumerator<int> while IEnumerable.GetEnumerator() is supposed to return IEnumerator, yet it return the generic version which is IEnumerator<int>, as it just returns GetEnumerator();. So clearly different return types. What am I missing here?


Solution

  • As is pointed out in the comments, an IEnumerator<T> implements IEnumerator so in essence an IE<T> "is a" IE. It's probably easier to see if we do this, which is fine:

    class Foo : IEnumerable<int>
    {
        private IEnumerator<int> x;
        
        public IEnumerator<int> GetEnumerator()
        {
            return x;
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return x;
        }
    }
    

    It doesn't work if we change the type of X to IEnumerator:

    class Foo : IEnumerable<int>
    {
        private IEnumerator x;
        
        public IEnumerator<int> GetEnumerator()
        {
            return x;
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return x;
        }
    }
    

    Because while an IE<T> is-a IE, it doesn't mean an IE is-a IE<T>, for similar reasons that e.g. a "string is-a object" but not necessarily a "object is-a string"

    Had it been this:

    class Lion:IAnimal{}
    
    class Zoo{
      Lion GetLion() { }
      IAnimal GetAnimal() { return GetLion(); }
    }
    

    ..you wouldn't even have questioned it :)