Skip to content

C# Interfaces and default method implementations

The upcoming C# 8.0 release came up the other day, or more specifically the inclusion of default implementations on interface methods. At first glance it seems akin to madness, blurring the line between implementation and inheritance. We already have abstract classes that cater for this, so why the need?

Taking a little time to dig a little deeper though, and I think it does make sense and could be extremely powerful. The caveat being that it isn’t abused, which it most certainly could be.

Using it looks to be pretty straight forward. You simply provide a method body on the interface definition like so:

using System.Threading;

interface IAnimal
{
    void Sleep()
    {
        Thread.Sleep(28800000);
    }
}

So far, so good. It still seems like this could be achieved by an Abstract class though. Which is true. We could make IAnimal an abstract class and implement it like so.

public abstract class Animal
{
    public virtual void Sleep()
    {
        Thread.Sleep(28800000);
    }
}

public class Human : Animal
{
    public void Eat()
    {
        Console.WriteLine("I am eating");
    }
}

Here we have a class ‘Human’ that inherits Sleep from the abstract animal class and adds it’s own method Eat. Both the virtual method on the abstract class and the default implementation on the interface give the same behaviour. A human that can Sleep and Eat.

Now however is where it gets interesting. If we did use an abstract class, that would be the end of the road. Our Human has already inherited from Animal, and can’t inherit from anything else as this would be multiple inheritance, something that is not possible in C#. However! Using the default method implementation on interfaces, we can continue on. Below I have created another two interfaces

interface IBritish
{
    void DrinkTea() 
    {
        Console.WriteLine("I am drinking tea");
    }
}

interface IItalian
{
    void DrinkCoffee() 
    {
        Console.WriteLine("I am drinking coffee");
    }
}

Now, since these are interfaces I can apply them to the class ‘Human’ on top of the IAnimal interface!

public class Human : IAnimal, IBritish
{
    public void Eat()
    {
        Console.WriteLine("I am eating");
    }
}

This now gives me a human that can Sleep, Eat and DrinkTea! Marvelous. Combining the IItalian interface as well we get a human that can Sleep, Eat, DrinkTea and DrinkCoffee.

This is a very basic and exaggerated example of Traits. By combining different functions that don’t necessarily have to be related, we can build up a custom class with specific functionality very quickly! Imagine we had another interface IProgrammer, who can WriteCode(). We could create classes that can WriteCode and DrinkTea, or WriteCode and DrinkCoffee, or WriteCode, DrinkTea and DrinkCoffee!

Something to note is that the default implimentation is tied to the interface, not the class that impliments it. With an Abstract class and inheritance you don’t have this concern.

public class Test()
{
    public void Example()
    {
        var personA = new Human();
       
        personA.DrinkTea(); //Won't work
        (IBritish)personA.DrinkTea(); //Will work

        IBritish personB = new Human();
        personB.DrinkTea(); //Will Work
    }
}

Hopefully that all makes sense!

Published inC#

Comments are closed.