How to return subtype in overridden method of subclass in C#?
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
Comments
-
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 over 15 yearsI've included the compiler error as the comment.
-
-
Jon Skeet over 15 yearsFirstly 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 over 15 yearsI 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 over 15 yearshe can cast the returnval wherever its needed as Derived
-
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 over 15 yearsNone 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 over 14 yearsSee this comment by Eric Lippert about why C# doesn't support it stackoverflow.com/questions/1319663/…