Вопрос

The List<T> class implements the IEnumerable<T> interface. It has a method GetEnumerator that returns a List<T>.Enumerator.

I have a class as below, which gives a compile error saying the return type of GetEnumerator doesn't match the interface.

public class InsertionSortedSet<T> : IEnumerable<T>
{
    public struct Enumerator : IEnumerator<T>
    {
        // Required interface implemented
    }

    // Other interface methods implemented

    public Enumerator GetEnumerator()
    {
        return new Enumerator(this);
    }
}

'Entities.Helpers.InsertionSortedSet' does not implement interface member 'System.Collections.Generic.IEnumerable.GetEnumerator()'. 'Entities.Helpers.InsertionSortedSet.GetEnumerator()' cannot implement 'System.Collections.Generic.IEnumerable.GetEnumerator()' because it does not have the matching return type of 'System.Collections.Generic.IEnumerator'.

Given that List<T> seems to return it's own Enumerator class (not the interface) and yet it does implement the Enumeration<T> interface I'm confused, as I can't see what i've got different to that class.

What's wrong with my setup that makes it fail, where List<T> works?


I want to return a InsertionSortedSet<T>.Enumerator rather than the interface as it avoids boxing, which I need to cut out.

Это было полезно?

Решение

It's complaining because GetEnumerator() returns IEnumerator<T> for the IEnumerable<T> interface. To satisfy, your type must return IEnumerator<T> (and an explicit one for IEnumerator as well).

But, many times it's desirable for a class to return a more specific type than the interface specifies, but interfaces don't allow for covariant return types like that. So to do this, you can do what List<T> does and have GetEnumerator() return your specific enumerator, but you must also implement explicit implementations for IEnumerable.GetEnumerator() that returns an IEnumerator and for IEnumerable<T>.GetEnumerator() that returns an IEnumerator<T>:

    // This is your specific version, like List<T> does
    public Enumerator GetEnumerator()
    {
        return new Enumerator(this);
    }

    // This is the one with the return value IEnumerator<T> expects
    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return new Enumerator(this);
    }

    // Plus, it also expects this as well to satisfy IEnumerable
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

If you look at List<T> you'll see that it implements GetEnumerator() three times:

  • Once explicitly for IEnumerable<T>
  • Once explicitly for Enumerable
  • Once with a very list-specific return

You could do the same in your class if you wish (which it sould like is the way you began) but if you do that you must explicitly implement IEnumerable<T>.GetEnumerator() and IEnumerable.GetEnumerator()

If you navigate to the definition, you can see the other definitions in the object browser by selecting the different interfaces it satisfies (or by assigning a List<T> instance to an IEnumerable or IEnumerable<T> reference and going to definition):

Screenshot of Object Explorer

Другие советы

To allow a class to be iterated using foreach no need to implement any interface. All what you need is implementing GetEnumerator method that returns your Enumerator<T>.

But if you want your class to support standard iteration interface IEnumerable<T> you may implement it explicity: IEnumerable<T>.GetEnumerator() { return GetEnumerator(); }

What you are looking for is called return type covariance, more here Does C# support return type covariance?

This can be achieved by using explicit implementation of interface to return IEnumerator<T> and implement public method of same name to return Enumerator.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top