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 returnMyType<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
Why Does Boolean.Tostring Output "True" and Not "True"
Generating Dll Assembly Dynamically at Run Time
C# (Mono) Linux Web Server Hosting with Consistent Static Variables Across Threads
How to Instantiate a Class Given Its String Name
Replace Multiple Characters in a C# String
Close a Messagebox After Several Seconds
Calling JavaScript Function from Codebehind
How to Build a JSON Object to Send to an Ajax Webservice
ASP.NET MVC 2 - Bind a Model's Property to a Different Named Value
How to Pass Parameters by Reference in Java
Differencebetween a Mutable and Immutable String in C#
Read the Value of an Attribute of a Method
Howto Implement Callback Interface from Unmanaged Dll to .Net App