Is there way to override return types in C#? If so how, and if not why and what is a recommended way of doing it?
My case is that I have an interface with an abstract base class and descendants of that. I would like to do this (ok not really, but as an example!) :
public interface Animal
{
Poo Excrement { get; }
}
public class AnimalBase
{
public virtual Poo Excrement { get { return new Poo(); } }
}
public class Dog
{
// No override, just return normal poo like normal animal
}
public class Cat
{
public override RadioactivePoo Excrement { get { return new RadioActivePoo(); } }
}
RadioactivePoo
of course inherits from Poo
.
My reason for wanting this is so that those who use Cat
objects could use the Excrement
property without having to cast the Poo
into RadioactivePoo
while for example the Cat
could still be part of an Animal
list where users may not necessarily be aware or care about their radioactive poo. Hope that made sense...
As far as I can see the compiler doesn't allow this at least. So I guess it is impossible. But what would you recommend as a solution to this?
What about a generic base class?
public class Poo { }
public class RadioactivePoo : Poo { }
public class BaseAnimal<PooType>
where PooType : Poo, new() {
PooType Excrement {
get { return new PooType(); }
}
}
public class Dog : BaseAnimal<Poo> { }
public class Cat : BaseAnimal<RadioactivePoo> { }
EDIT: A new solution, using extension methods and a marker interface...
public class Poo { }
public class RadioactivePoo : Poo { }
// just a marker interface, to get the poo type
public interface IPooProvider<PooType> { }
// Extension method to get the correct type of excrement
public static class IPooProviderExtension {
public static PooType StronglyTypedExcrement<PooType>(
this IPooProvider<PooType> iPooProvider)
where PooType : Poo {
BaseAnimal animal = iPooProvider as BaseAnimal;
if (null == animal) {
throw new InvalidArgumentException("iPooProvider must be a BaseAnimal.");
}
return (PooType)animal.Excrement;
}
}
public class BaseAnimal {
public virtual Poo Excrement {
get { return new Poo(); }
}
}
public class Dog : BaseAnimal, IPooProvider<Poo> { }
public class Cat : BaseAnimal, IPooProvider<RadioactivePoo> {
public override Poo Excrement {
get { return new RadioactivePoo(); }
}
}
class Program {
static void Main(string[] args) {
Dog dog = new Dog();
Poo dogPoo = dog.Excrement;
Cat cat = new Cat();
RadioactivePoo catPoo = cat.StronglyTypedExcrement();
}
}
This way Dog and Cat both inherit from Animal (as remarked in the comments, my first solution did not preserve the inheritance).
It's necessary to mark explicitly the classes with the marker interface, which is painful, but maybe this could give you some ideas...
SECOND EDIT @Svish: I modified the code to show explitly that the extension method is not enforcing in any way the fact that iPooProvider
inherits from BaseAnimal
. What do you mean by "even more strongly-typed"?