什么是 C# 默认接口方法
从 C# 8.0 开始,接口可以包含带有实现的成员(即“默认接口方法”),这打破了过去接口只能声明、不能实现的限制。它不是为了替代抽象类,而是为了解决接口演化问题:在不破坏已有实现类的前提下,向接口添加新方法。
关键点:
default interface method必须是
public(不能是
private或
protected),且不能是
static(C# 8–11 中不允许;C# 11+ 才支持
static abstract和
static virtual接口方法,但那是另一回事)。
如何定义带默认实现的接口方法
语法上就是在接口里写一个完整的方法体,不加
abstract,也不加
virtual—— 它天然就是可被重写的(除非实现类显式用
sealed修饰重写)。 必须使用 C# 8.0+ 编译器,且项目 SDK 版本 ≥
netcoreapp3.0或
net5.0及以上 接口方法签名后直接跟
{ ... },例如:void Log() { Console.WriteLine("default"); }
可以访问接口中的 static成员(C# 8+ 支持接口中定义
static字段和方法),但不能访问实例状态(因为没有
this上下文) 如果实现类未提供自己的版本,调用的就是接口里的默认实现
实现类是否必须重写默认接口方法
不需要。实现类可以完全忽略默认方法,直接继承行为;也可以选择
override它(需用
public override显式声明);还可以用
sealed override阻止进一步重写。
常见误区:
override不是可选修饰符——如果你写了实现,就必须加
override,否则编译报错:
'ClassName.MethodName()' does not implement interface member 'IInterface.MethodName()'。
示例:
interface ILogger
{
void Log() => Console.WriteLine("default log");
}
<p>class ConsoleLogger : ILogger
{
public override void Log() => Console.WriteLine("console log"); // ✅ 必须加 override
}</p><p>class NullLogger : ILogger
{
// ✅ 什么都不写,就用接口默认实现
}默认接口方法的调用歧义与显式实现
当一个类实现多个接口,且这些接口都提供了同名默认方法时,编译器会报错:
Ambiguity between 'I1.M()' and 'I2.M()'。此时必须在类中显式提供实现,或使用显式接口实现来消歧。 显式实现写法:
void I1.M() { ... } 和 void I2.M() { ... },各自独立
若只希望某一个默认行为生效,可在类中写 public override void M()并在里面调用特定接口的默认实现:
((I1)this).M();注意:不能在默认接口方法体内用
this调用其他接口默认方法(因为
this在接口中不可用) 多层继承链中,接口默认方法不会“向上查找”,它只属于定义它的那个接口
真正容易被忽略的是:默认接口方法无法访问实现类的字段或属性,也不能调用
base(因为没有基类概念)。它看起来像“实现”,实际更像“契约附带的兜底逻辑”。
