Может ли класс C# вызвать метод интерфейса по умолчанию из собственной реализации?
Если у меня есть такой метод интерфейса по умолчанию:
public interface IGreeter
{
void SayHello(string name) => System.Console.WriteLine($"Hello {name}!");
}
Можно ли в моей конкретной реализации вызвать этот метод по умолчанию?
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!!");
}
}
Так что призыв:
var greeter = new HappyGreeter() as IGreeter;
greeter.SayHello("Pippy");
Результатов в этом:
// Hello Pippy!
// I hope you're doing great!!
Действительно, вызов метода интерфейса C# по умолчанию из реализации класса показывает, что я могу вызвать метод, который не реализует мой класс, но, как несколько ожидалось, добавление вызова к((IGreeter)this).SayHello(name);
внутри HappyGreeter.SaysHello
вызывает переполнение стека.
3 ответа
Насколько я знаю, вы не можете вызвать реализацию метода интерфейса по умолчанию при наследовании класса (хотя предложения были). Но вы можете вызвать это из наследуемого интерфейса:
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
В моем первоначальном ответе очень хотелось показать, что вы можете позвонить base
при наследовании интерфейса, но, как предложил Alexei Levenkov в комментариях, более чистый способ в этом конкретном случае будет примерно таким:
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!!");
}
}
Есть довольно простой способ справиться с этим:
- Поместите код реализации метода по умолчанию в отдельный статический метод.
- Вызовите этот статический метод из метода реализации по умолчанию.
- Вызовите этот статический метод в верхней части реализации класса метода интерфейса.
Пример:
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");
}
}
Пример вывода:
Hello Bob!
I hope you're doing great!!
Я знаю, что это не ответ на вопрос, но следующий подход также можно использовать для имитации base
функциональность:
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!!");
}
}