C#: Overriding Return Types

C#: Overriding return types

I know there are a lot of solutions for this problem already but I think I've come up with one that fixes the issues I had with the existing solutions.

I wasn't happy with the some of the existing solutions for the following reasons:

  • Paolo Tedesco's first solution: Cat and Dog do not have a common base class.
  • Paolo Tedesco's second solution: It is a bit complicated and hard to read.
  • Daniel Daranas's solution: This works but it would clutter up your code with a lot of unnecessary casting and Debug.Assert() statements.
  • hjb417's solutions: This solution doesn't let you keep your logic in a base class. The logic is pretty trivial in this example (calling a constructor) but in a real world example it wouldn't be.

My Solution

This solution should overcome all of the issues I mentioned above by using both generics and method hiding.

public class Poo { }
public class RadioactivePoo : Poo { }

interface IAnimal
{
Poo Excrement { get; }
}

public class BaseAnimal<PooType> : IAnimal
where PooType : Poo, new()
{
Poo IAnimal.Excrement { get { return (Poo)this.Excrement; } }

public PooType Excrement
{
get { return new PooType(); }
}
}

public class Dog : BaseAnimal<Poo> { }
public class Cat : BaseAnimal<RadioactivePoo> { }

With this solution you don't need to override anything in Dog OR Cat! Here is some sample usage:

Cat bruce = new Cat();
IAnimal bruceAsAnimal = bruce as IAnimal;
Console.WriteLine(bruce.Excrement.ToString());
Console.WriteLine(bruceAsAnimal.Excrement.ToString());

This will output: "RadioactivePoo" twice which shows that polymorphism has not been broken.

Further Reading

  • Explicit Interface Implementation
  • new Modifier. I didn't use it in this simplified solution but you may need it in a more complicated solution. For example if you wanted to create an interface for BaseAnimal then you would need to use it in your decleration of "PooType Excrement".
  • out Generic Modifier (Covariance). Again I didn't use it in this solution but if you wanted to do something like return MyType<Poo> from IAnimal and return MyType<PooType> from BaseAnimal then you would need to use it to be able to cast between the two.

C# Possible to override a return type on derived classes?

Short answer is no.

Think of it, how will you use it later?

base b = new derivedc ()

And then? what will be the return type of b.name() ? string? foo?

You can however use generics to control it (although i'm not sure if it'll fit your use case):

class base<T>{
....
public virtual T name();
....
}

class deriveda : base<string>{
....
public override string name();
....
}

class derivedb : base<string>{
....
public override string name();
....
}

class derivedc : base<foo>{
....
public override foo name();
....
}

Overriding method to change return type

Or am I doing something totally daft? :-)

Yes, you are. You can't change the return type of a method by overriding it. I don't understand it in your sample anyway. Just leave the return type as it was and return a new ExternalObjectStub. This works, because ExternalObjectStub derives from ExternalObject.

Changing the return type by hiding the base member with new as you do it, is generally a very bad idea, because it leads to a class that can't be used in a polymorphic way. This is exactly what you are experiencing here: If the type of the variable that holds the reference is of type ParentClass it calls the method in ParentClass, even if the instance really is of type ChildClass, because ChildClass doesn't provide an overriden implementation of GetExternalObject.

Change return type to derived type during override

The only way to do this properly is using generics like this:

public interface A<T> where T : A<T>
{
T method1();
}

Then B looks like this:

public interface B : A<B>
{
void otherMethod();
}

And finally, implementing a class would go like this:

public class Bravo : B
{
public B method1() { return null; }
public void otherMethod() { }
}

However, you can use the new keyword to shadow a method in an interface, but this isn't a great idea as it makes it harder to reason about your code as it breaks normal inheritance.

Try this:

public interface A
{
A method1();
}

public interface B : A
{
new B method1();
void otherMethod();
}

public class Bravo : B
{
A A.method1() { return null; }
public B method1() { return null; }
public void otherMethod() { }
}

Overriding property return type, C#

Return type cannot be overridden, because return type is part of the fixed part of the method's signature/property type. You can, however, do method/property hiding and change the return type using keyword new:

public new string Timezone { get; set; } //note the new keyword

Also, if you want to do overriding, you should put virtual keyword in the original (base) class and use override keyword in the derived class:

public class A: SomeClass
{
public virtual TimeZoneInfo Timezone { get; set; } //note virtual keyword
public A()
{
Timezone = TimeZoneInfo.Utc;
}
}

public class B: A
{
public override TimeZoneInfo Timezone { get; set; } //note override keyword, return type is not changed
public B()
{
}
}


Related Topics



Leave a reply



Submit