How to return subtype in overridden method of subclass in C#?

14,616

Solution 1

Unfortunately no, covariant return types aren't supported in C# for method overriding. (Ditto contravariant parameter types.)

If you're implementing an interface you can implement it explicitly with the "weak" version and also provide a public version with the stronger contract. For simple overriding of a parent class, you don't have this luxury I'm afraid :(

(EDIT: Marc has a reasonable solution - although it's pretty ugly, and method hiding is generally a bad thing for readability. No offence meant, Marc ;)

I believe this is actually a CLR restriction, not just a language one - but I could well be wrong.

(As a matter of history, Java (the language) had the same restriction until 1.5 - but it gained covariance at the same time as generics.)

Solution 2

You could make the class generic if that doesn't bothers you:

    class BaseReturnType { }
    class DerivedReturnType : BaseReturnType { }

    abstract class BaseClass<T> where T : BaseReturnType
    {
        public abstract T PolymorphicMethod();
    }

    class DerivedClass : BaseClass<DerivedReturnType>
    {
        // Error: return type must be 'BaseReturnType' to match 
        // overridden member 'BaseClass.PolymorphicMethod()'
        public override DerivedReturnType PolymorphicMethod()
        {
            return new DerivedReturnType();
        }
    }

Solution 3

You can do this if you introduce an extra method to override (since you can't override and new a method with the same name in the same type):

abstract class BaseClass
{
    public BaseReturnType PolymorphicMethod()
    { return PolymorphicMethodCore();}

    protected abstract BaseReturnType PolymorphicMethodCore();
}

class DerivedClass : BaseClass
{
    protected override BaseReturnType PolymorphicMethodCore()
    { return PolymorphicMethod(); }

    public new DerivedReturnType PolymorphicMethod()
    { return new DerivedReturnType(); }
}

Now you have a PolymorphicMethod method at each level with the correct type.

Solution 4

Generics are not necessarily the way to go. In particular, type(of Derived) is not considered a type(of Base).

First, add a new method to your derived class which will return the value with the correct type. Second, mark the overriding method not-overridable and have it delegate to your new method.

That's it. You've solved your problem. Child classes won't be able to re-expand the type because they must override your new method.

I apologize if the code isn't quite right; I'm used to VB.net.

abstract class C1 {
    public abstract IEnumerable<Byte> F1();
}
class C2 : C1 {
    public sealed override IEnumerable<Byte> F1() {
        Return F2();
    }
    public overridable IList<Byte> F2() {
        Return {1, 2, 3, 4};
    }
}

Solution 5

class BaseReturnType { }
class DerivedReturnType : BaseReturnType { }

abstract class BaseClass {
    public abstract BaseReturnType PolymorphicMethod();
}

class DerivedClass : BaseClass {
    // Error: return type must be 'BaseReturnType' to match 
    // overridden member 'BaseClass.PolymorphicMethod()'
    public override BaseReturnType PolymorphicMethod() { 
        return new DerivedReturnType(); 
    }
}

this should work

Share:
14,616
B Bulfin
Author by

B Bulfin

I like bikes. For more information, see here.

Updated on June 07, 2022

Comments

  • B Bulfin
    B Bulfin about 2 years

    I have a subclass with an over-ridden method that I know always returns a particular subtype of the return type declared in the base class. If I write the code this way, it won't compile. Since that probably doesn't make sense, let me give a code example:

    class BaseReturnType { }
    class DerivedReturnType : BaseReturnType { }
    
    abstract class BaseClass {
        public abstract BaseReturnType PolymorphicMethod();
    }
    
    class DerivedClass : BaseClass {
        // Compile Error: return type must be 'BaseReturnType' to match 
        // overridden member 'BaseClass.PolymorphicMethod()'
        public override DerivedReturnType PolymorphicMethod() { 
            return new DerivedReturnType(); 
        }
    }
    

    Is there any way to accomplish this in C#? If not, what's the best way to achieve something similar? And why isn't it allowed? It doesn't seem to allow any logical inconsistency, since any object returned from the over-ridden method still is BaseReturnType. Maybe there is something I hadn't considered though. Or maybe the reason is technological or historical.

    • B Bulfin
      B Bulfin over 15 years
      I've included the compiler error as the comment.
  • Jon Skeet
    Jon Skeet over 15 years
    Firstly that's not always applicable, and secondly it may not help anyway - you might want to indicate that you're returning an implementation of ISpecificInterface where the base class declares that it will return IGeneralInterface.
  • B Bulfin
    B Bulfin over 15 years
    I know this is possible, but then it requires you to cast (new DerivedClass()).PolymorphicMethod() if you want to use it as a DerivedReturnType. That may be what I end up doing, but I don't like casting if I can avoid it.
  • anand
    anand over 15 years
    he can cast the returnval wherever its needed as Derived
  • Jon Skeet
    Jon Skeet over 15 years
    @anand: Yes, but that's painful, as well as making a check necessary at execution time when we should be able to explain that it's valid at compile time.
  • Marc Gravell
    Marc Gravell over 15 years
    None taken ;-p Note, however, that this is exactly the pattern used by a lot of the .NET BCL - for example DbConnection has CreateCommand, which shims thru the "protected abstract" CreateDbCommand.
  • Ben Lings
    Ben Lings over 14 years
    See this comment by Eric Lippert about why C# doesn't support it stackoverflow.com/questions/1319663/…