D. Patrick
D. Patrick

Reputation: 3022

Can a C# class call an interface's default interface method from its own implementation?

If I have a default interface method like this:

public interface IGreeter
{
    void SayHello(string name) => System.Console.WriteLine($"Hello {name}!");
}

Can I have my concrete implementation call that default method?

public class HappyGreeter : IGreeter
{
    public void SayHello(string name)
    {
        // what can I put here to call the default method?
        System.Console.WriteLine("I hope you're doing great!!");
    }
}

So that calling:

var greeter = new HappyGreeter() as IGreeter;
greeter.SayHello("Pippy");

Results in this:

// Hello Pippy!
// I hope you're doing great!!

Indeed Calling C# interface default method from implementing class shows that I can call method that my class does not implement, but as somewhat expected adding call to ((IGreeter)this).SayHello(name); inside HappyGreeter.SaysHello causes stack overflow.

Upvotes: 15

Views: 2361

Answers (3)

Guru Stron
Guru Stron

Reputation: 141895

As far as I know you can't invoke default interface method implementation in inheriting class (though there were proposals). But you can call it from inheriting interface:

public class HappyGreeter : IGreeter
{
    private interface IWorkAround : IGreeter
    {
        public void SayHello(string name)
        {
            (this as IGreeter).SayHello(name);
            System.Console.WriteLine("I hope you're doing great!!");
        }
    }

    private class WorkAround : IWorkAround {}

    public void SayHello(string name)
    {
        ((IWorkAround)new WorkAround()).SayHello(name);
    }
}

UPD

In my original answer I was to much focused on showing that you can call base one in an inheriting interface, but as @Alexei Levenkov suggested in comments cleaner way in this particular case would be something like the following:

public class HappyGreeter : IGreeter
{
    private class WorkAround : IGreeter { }
    private static readonly IGreeter _workAround = new WorkAround();

    public void SayHello(string name)
    {
        _workAround.SayHello(name);
        System.Console.WriteLine("I hope you're doing great!!");
    }
} 

Upvotes: 6

Bob Bryan
Bob Bryan

Reputation: 3837

There is a very simple way to handle this:

  1. Declare the default method as static. Don't worry, you will still be able to override it in a class that inherits from it.
  2. Call the default method using the same type of syntax when calling a static method of a class, only substitute the interface name for the class name.

This code applies to C#8 or later, and it won't work if building against the .NET Framework. I ran it on Windows 10 with C#9, running on .NET 6, preview 5.

Example:

public interface IGreeter
{
   private static int DisplayCount = 0;
   public static void SayHello(string name)
   {
      DisplayCount++;
      Console.WriteLine($"Hello {name}! This method has been called {DisplayCount} times.");
   }
}

public class HappyGreeter : IGreeter
{
   public void SayHello(string name)
   {
      // what can I put here to call the default method?
      IGreeter.SayHello(name);
      Console.WriteLine("I hope you're doing great!!");
   }
}

public class CS8NewFeatures
{
   // This class holds the code for the new C# 8 features.
   //
   public void RunTests()
   {
      TestGreeting();
   }

   private void TestGreeting()
   {
      // Tests if a default method may be called after a class has implemented it.
      //
      var hg = new HappyGreeter();
      hg.SayHello("Pippy");
      hg.SayHello("Bob");
      hg.SayHello("Becky");
   }
}

Example Output:

Hello Pippy! This method has been called 1 times.
I hope you're doing great!!
Hello Bob! This method has been called 2 times.
I hope you're doing great!!
Hello Becky! This method has been called 3 times.
I hope you're doing great!!

Static fields are also now allowed in interfaces as this example shows.

If you can't use a static interface method for some reason, then you can always rely on the following technique:

  1. Put the default method implementation code into a separate static method.
  2. Call this static method from the default implementation method.
  3. Call this static method at the top of the class implementation of the interface method.

Example:

public class DefaultMethods
{
   // This class is used to show that a static method may be called by a default interface method.
   //
   public static void SayHello(string name) => Console.WriteLine($"Hello {name}!");
}

public interface IGreeter
{
   void SayHello(string name) => DefaultMethods.SayHello(name);
}

public class HappyGreeter : IGreeter
{
   public void SayHello(string name)
   {
      // what can I put here to call the default method?
      DefaultMethods.SayHello(name);
      Console.WriteLine("I hope you're doing great!!");
   }
}

public class CS8NewFeatures
{
   // This class holds the code for the new C# 8 features.
   //
   public void RunTests()
   {
      TestGreeting();
   }

   private void TestGreeting()
   {
      // Tests if a default method may be called after a class has implemented it.
      //
      var hg = new HappyGreeter();
      hg.SayHello("Bob");
   }
}

Sample Output:

Hello Bob!
I hope you're doing great!!

Upvotes: 5

Iliar Turdushev
Iliar Turdushev

Reputation: 5213

I know that this is not an answer to the question, but the next approach also can be used to emulate base functionality:

public interface IGreeter
{
    void SayHello(string name) => BaseSayHello(name);

    // This static method can be used in implementers of "IGreeter"
    // to emulate "base" functionality.
    protected static void BaseSayHello(string name) => System.Console.WriteLine($"Hello {name}!");
}

public class HappyGreeter : IGreeter
{
    public void SayHello(string name)
    {
        IGreeter.BaseSayHello(name);
        Console.WriteLine("I hope you're doing great!!");
    }
}

Upvotes: 2

Related Questions