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# 接口默认方法表明我可以调用我的类未实现的方法,但正如预期的那样,在HappyGreeter.SaysHello内部添加对((IGreeter)this).SayHello(name);的调用会导致堆栈溢出。

据我所知,您无法在继承类中调用默认接口方法实现(尽管有建议(。但是你可以从继承接口调用它:

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 one,但正如 Levenkov @Alexei 在评论中建议的那样,在这种特殊情况下,更简洁的方式如下所示:

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!!");
}
} 

有一个非常简单的方法来解决这个问题:

  1. 将默认方法声明为静态方法。别担心,您仍然可以在继承自它的类中覆盖它。
  2. 调用类
  3. 的静态方法时,使用相同类型的语法调用默认方法,仅将接口名称替换为类名。

此代码适用于 C#8 或更高版本,如果针对 .NET Framework 进行构建,它将不起作用。我在Windows 10上运行它与C#9,运行在.NET 6,预览版5上。

例:

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");
}
}

示例输出:

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!!

接口中现在也允许使用静态字段,如此示例所示。

如果由于某种原因无法使用静态接口方法,则始终可以依赖以下技术:

  1. 将默认方法实现代码放入单独的静态方法中。
  2. 从默认实现方法调用此静态方法。
  3. 在接口方法的类实现的顶部调用此静态方法。

例:

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!!");
}
}

最新更新