Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 900
D. Patrick Avatar asked Jun 11 '20 21:06

D. Patrick


People also ask

How much does it cost to recharge AC?

Most homeowners will pay in the range of $200 to $400 for a refill, depending on the type and size of their HVAC unit. If you own a larger r22 unit, you may have to spend $600 or more.

Why is my car not accepting Freon?

It's possible that an internal component is broken. You will have to fix the compressor before you can recharge the Freon. If you see a very high pressure on the high side gauge and very low pressure on the low side gauge, there's a Freon blockage. Start by checking the expansion valve or orifice tube.

Will AutoZone put Freon in my car?

If you need help performing this, or any AC recharge or service, check out our list of preferred shops in your area that can help. Or, if you'd like to tackle the job yourself, AutoZone has all the tools and refrigerant to service your R-134A or R-12 vehicle.


3 Answers

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 too much wanted to show that you can call base in inheriting interface, but as @Alexei Levenkov suggested in comments cleaner way in this particular case would be something like this:

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!!");
    }
} 
like image 58
Guru Stron Avatar answered Sep 22 '22 13:09

Guru Stron


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!!
like image 23
Bob Bryan Avatar answered Sep 22 '22 13:09

Bob Bryan


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!!");
    }
}
like image 27
Iliar Turdushev Avatar answered Sep 21 '22 13:09

Iliar Turdushev