views:

83

answers:

3

I've been reading through the book Working Effectively with Legacy Code and I've been playing around with the concept of overriding difficult to test methods in unit tests via the creation of a fake. I put together an example of what I thought would work and it ended up behaving differently than I had been expecting. I think I've just discovered a hole in my understanding of how inheritance and method overloading works in C# and I was wondering if someone could help me understand what's going on here.

I've got the following interface:

public interface IAnimal
{
    void MakeSound();
    void Move();
}

I then create an implementation of the animal interface as follows:

public class Dog : IAnimal
{

public void MakeSound()
{
    Console.WriteLine("Woof");
}

public void Move()
{
    Console.WriteLine("Moved");
}

}

When I use this class as follows:

IAnimal myanimal = new Dog();
myanimal.MakeSound();
myanimal.Move();

I get the following output: Woof Moved

Now, lets pretend that I'm needing to unit test the Dog class but one of the methods, MakeSound(), needs to be overridden because it is making the class difficult to test for some reason.

I create a fake dog by extending the Dog class and creating a method for MakeSound

public class FakeDog : Dog
{
    public void MakeSound()
    {
         Console.WriteLine("Bark");
    }
}

When I use this class as follows:

IAnimal myanimal = new FakeDog();
myanimal.MakeSound();
myanimal.Move();

I get the following output: Woof Moved

I had been expecting it to have been: Bark Moved

However, if I then have the FakeDog class implement the animal interface and use it:

public class FakeDog : Dog, IAnimal
{
    public void MakeSound()
    {
         Console.WriteLine("Bark");
    }
}

I get the following output: Bark Moved

I'm just wanting to understand the reason why this now overrides the method as I had been expecting when I had just been extended the Dog class. Can anyone set me straight on this?

+2  A: 

(Sorry for answering with a question, but you might genuinely find this experiment informative) What happens when you implement dog as follows:

public class Dog : IAnimal
{

public virtual void MakeSound()
{
    Console.WriteLine("Woof");
}

//...

Note the "virtual"

Rob Fonseca-Ensor
When I do that, when I extend the Dog class I can override the method by using the override keyword. In my case I'm trying to see how things would work if I didn't want to make an existing classes methods virtual because most legacy code that I encounter at work don't have the methods marked as virtual
mezoid
+1  A: 

You need to declare the MakeSound method as virtual in the Dog class and override it in the FakeDog class:

public class Dog : IAnimal
{
    public virtual void MakeSound()
    {
        Console.WriteLine("Woof");
    }

    public virtual void Move()
    {
        Console.WriteLine("Moved");
    }
}

public class FakeDog : Dog
{
    public override void MakeSound()
    {
        Console.WriteLine("Bark");
    }
}
Darin Dimitrov
+4  A: 

In the first case you're creating a new method which hides the original implementation of IAnimal.MakeSound. You should have seen a warning suggesting that you use the new keyword to make this explicit.

In the second case you're re-implementing IAnimal. Implementing an interface doesn't require the override keyword (although it might have been nice if the language designers had required that).

To avoid re-implementing the interface, you could make MakeSound virtual in Dog, and then explicitly override it in FakeDog. At that point there's only one possible resolution involved, and everything is simpler to understand. I try to avoid reimplementation and method hiding whenever possible.

Jon Skeet
The reason I didn't see the warning is because I was conducting my experiment in LinqPad. Thanks for the explanation though. I'll have to remember that when I use the Extract and Override Method refactoring that I'll need to create the method as virtual in order to properly override the method.
mezoid