Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c#

inheritance

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.

like image 473
recursive Avatar asked Jan 07 '09 20:01

recursive


People also ask

Can we change return type of overridden method?

From Java 5 onwards, we can override a method by changing its return type only by abiding the condition that return type is a subclass of that of overridden method return type.

What rules apply to return types for overridden methods?

Rules regarding covariant return type A subclass' overriding method should match its superclass or subclass' return type if the overriding method returns the same type. Underlining methods in subclasses should not override methods in the parent class and vice versa.

Can we change the return type of overridden method in subclass C#?

You cannot change the return type of method during overriding.

What happens if we change the arguments of overriding method?

4) What happens if we change the arguments of overriding method? If we change the arguments of overriding method, then that method will be treated as overloaded not overridden.


6 Answers

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.)

like image 146
Jon Skeet Avatar answered Oct 10 '22 00:10

Jon Skeet


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();
        }
    }
like image 45
Stormenet Avatar answered Oct 10 '22 01:10

Stormenet


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.

like image 23
Marc Gravell Avatar answered Oct 10 '22 00:10

Marc Gravell


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};
    }
}
like image 33
Craig Gidney Avatar answered Oct 10 '22 00:10

Craig Gidney


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

like image 30
anand Avatar answered Oct 10 '22 00:10

anand


Change your method signature on Derived class to:

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

C# doesn't support variant return types. You can check out this post for a way to do this using Generics...http://srtsolutions.com/blogs/billwagner/archive/2005/06/17/covaraint-return-types-in-c.aspx

Here's a sample using Generics in your model:

public class BaseReturnType
{
}
public class DerivedReturnType : BaseReturnType
{
}

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

}

public class DerviedClass : BaseClass<DerivedReturnType>
{
    public override DerivedReturnType PolymorphicMethod()
    {
        throw new NotImplementedException();
    }
}
like image 41
JoshBerke Avatar answered Oct 10 '22 01:10

JoshBerke