views:

1072

answers:

9

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?

A: 

It might help if RadioactivePoo is derived from poo and then use generics.

Bobby Alexander
+15  A: 

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

Paolo Tedesco
That seems like an excellent solution.
GoodEnough
Was just thinking the same thing.
DoctaJonez
Dont you loose out on pollymorphism between Dog and Cat?
almog.ori
What if there were other types you would like to override as well? You could technically end up with a whole bunch of type arguments. Which I think I might have found annoying... but yes, this is a solution.
Svish
@Svish: I imagine once that happens, it's time to use a dependency injection framework.
Brian
How does the StronglyTypedExcrement method know that iPooProvider is a BaseAnimal? Does it just guess? Or is it something I don't see? Would it be possible to make that method even more strongly typed?
Svish
From what I know, it ensures that it descends from "BaseAnimal", and anything that descends from that "can poo", as specified by the "virtual" excrement property, meaning that every animal descending from baseanimal shall have to provide a method to produce poo through excrement. Any clearer?
MrZombie
And from what I know, correct me if I'm wrong (really, I mean it, I wanna learn too! :P), but "iPooProvider"'s call to "Excrement" naturally will invoke the Excrement method from the animal's class (in that case, "cat"'s one)
MrZombie
+2  A: 

Correct me if im wrong but isnt the whole point of pollymorphism to be able to return RadioActivePoo if it inherits from Poo, the contract would be the same as the abstract class but just return RadioActivePoo()

almog.ori
You are perfectly right, but he wants to avoid the extra cast and some stronger-typing, which is mostly what generics are for...
Paolo Tedesco
+9  A: 

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.

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.

Daniel Daranas
What is the ENSURE clause? How would that work? Is it an attribute in .Net?
Svish
In .Net and before seeing .Net 4.0's Code Contracts, I write ENSURE(x) clauses as simply "Debug.Assert(x)". For further references see for example http://archive.eiffel.com/doc/manuals/technology/contract/page.html or Object Oriented Software Construction, 2nd Edition, by Bertrand Meyer (1994) chapter 11.
Daniel Daranas
"I would use them for a better reason than just returning radioactive poo - but that's just me" belongs in my list of favorite own quotes :)
Daniel Daranas
A: 

Try this:

namespace ClassLibrary1
{
    public interface Animal
    {   
        Poo Excrement { get; }
    }

    public class Poo
    {
    }

    public class RadioactivePoo
    {
    }

    public class AnimalBase<T>
    {   
        public virtual T Excrement
        { 
            get { return default(T); } 
        }
    }


    public class Dog : AnimalBase<Poo>
    {  
        // No override, just return normal poo like normal animal
    }

    public class Cat : AnimalBase<RadioactivePoo>
    {  
        public override RadioactivePoo Excrement 
        {
            get { return new RadioactivePoo(); } 
        }
    }
}
Shiraz Bhaiji
+1  A: 

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.

Rasmus Faber
A: 

It's not possible. C# and Java are not truly object oriented. Inheritance is strongly frowned upon. While types are not treated as first class object factories.

The future looks pretty complex as we seek to compensate.

George
+1  A: 

Why not define a protected virtual method that creates the 'Excrement' and keep the public property that returns the 'Excrement' non virtual. Then derived classes can override the return type of the base class.

In the following example, I make 'Excrement' non-virtual but provide the property ExcrementImpl to allow derived classes to provide the proper 'Poo'. Derived types can then override the return type of 'Excrement' by hiding the base class implementation.

E.x.:

namepace ConsoleApplication8

{
public class Poo { }

public class RadioactivePoo : Poo { }

public interface Animal
{
    Poo Excrement { get; }
}

public class AnimalBase
{
    public Poo Excrement { get { return ExcrementImpl; } }

    protected virtual Poo ExcrementImpl
    {
        get { return new Poo(); }
    }
}

public class Dog : AnimalBase
{
    // No override, just return normal poo like normal animal
}

public class Cat : AnimalBase
{
    protected override Poo ExcrementImpl
    {
        get { return new RadioactivePoo(); }
    }

    public new RadioactivePoo Excrement { get { return (RadioactivePoo)ExcrementImpl; } }
}
}
hjb417
A: 

I think I've found a way that doesn't depend on generics or extension methods, but rather method hiding. It can break polymorphism, however, so be especially careful if you further inherit from Cat.

I hope this post could still help somebody, despite being 8 months late.

public interface Animal
{
    Poo Excrement { get; }
}

public class Poo
{
}

public class RadioActivePoo : Poo
{
}

public class AnimalBase : Animal
{
    public virtual Poo Excrement { get { return new Poo(); } }
}

public class Dog : AnimalBase
{
    // No override, just return normal poo like normal animal
}

public class CatBase : AnimalBase
{
    public override Poo Excrement { get { return new RadioActivePoo(); } }
}

public class Cat : CatBase
{
    public new RadioActivePoo Excrement { get { return (RadioActivePoo) base.Excrement; } }
}
Cybis
Aack, never mind. I didn't realize hjb417 already posted a similar solution. At least mine doesn't require modifying the base class.
Cybis