romato
romato

Reputation: 35

Return Type Covariance Error with IEnumerable<T>

I define the following four classes:

    class X 
    {
        public X() {}
    }

    class A : IEnumerable<X>
    {
        public IEnumerator<X> GetEnumerator()
        {
            yield return new X();
        }

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

    class Foo
    {
        public virtual IEnumerable<X> Values { get; set; }
    }

    class Bar : Foo
    {
        public override A Values { get; set; }
    }

Foo is a class with a virtual property of type IEnumerable<X>, and derived class Bar overrides this property with an instance of class A, which derives from IEnumerable<X>. I expect return type covariance, but instead I encounter the error

'Bar.Values': type must be 'IEnumerable<X>' to match overriden member 'Foo.Values'

even though class A clearly implements IEnumerable<X>. What am I missing here? Why does the override type not work in this case?

Upvotes: 0

Views: 50

Answers (1)

Enigmativity
Enigmativity

Reputation: 117144

Let's introduce a new typed called B.

class B : IEnumerable<X>
{
    public IEnumerator<X> GetEnumerator() { yield return new X(); }
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

Now my implementation of Foo could be like this:

class Foo
{
    public virtual IEnumerable<X> Values { get; set; } = new B();
}

Perfectly legal.

Now let's implement a default Bar, but with A as the type of Values.

class Bar : Foo
{
    public override A Values
    {
        get => base.Values;
        set => base.Values = value;
    }
}

The get is trying to return the value from base.Values which is an instance of B, not A.

Bar does not know what types Foo might actually return so they return type must be the most general possible.

That's why this isn't allowed.

Upvotes: 3

Related Questions