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?


Solution 1:

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"?

Solution 2:

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.

Solution 3:

This is called return type covariance and is not supported in C# or .NET in general, despite some people's wishes.

What I would do is keep the same signature but add an additional ENSURE clause to the derived class in which I ensure that this one returns a RadioActivePoo. So, in short, I'd do via design by contract what I can't do via syntax.

Others prefer to fake it instead. It's ok, I guess, but I tend to economize "infrastructure" lines of code. If the semantics of the code are clear enough, I'm happy, and design by contract lets me achieve that, although it is not a compile time mechanism.

The same for generics, which other answers suggest. I would use them for a better reason than just returning radioactive poo - but that's just me.

Solution 4:

There is also this option (explicit interface-implementation)

public class Cat:Animal
{
  Poo Animal.Excrement { get { return Excrement; } }
  public RadioactivePoo Excrement { get { return new RadioactivePoo(); } }
}

You lose the ability to use the base-class to implement Cat, but on the plus-side, you keep the polymorphism between Cat and Dog.

But I doubt the added complexity is worth it.