Reputation: 3022
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
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
Reputation: 3837
There is a very simple way to handle this:
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:
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
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