必须在.csproj中显式设置8.0或更高版本,否则默认接口方法无法使用;接口默认方法只能用public(可省略),禁止private/internal/abstract/virtual等修饰符;重写时必须写public override,多接口同名默认方法需显式实现并可用ia.base.m()调用。

必须显式启用 C# 8.0+ 语言版本,否则 Log 方法体直接被编译器忽略或报错 CS8701。
怎么在 .csproj 里正确启用默认接口方法
不是装了新 SDK 就自动生效——VS 或 dotnet CLI 默认仍可能用 C# 7.3。关键看项目文件是否明确声明语言版本。
-
<langversion>8.0</langversion>或更高(如12.0)必须出现在.csproj的某个<propertygroup></propertygroup>中 - 若用
Directory.Build.props统一管理,要确认该文件被实际加载(可通过dotnet msbuild -preprocess:out.xml验证) - ASP.NET Core 模板常锁定
LangVersion,需手动覆盖;检查是否被<targetframework>net6.0</targetframework>间接压制(.NET 6 默认 C# 10,但旧项目可能未升级) - 在 VS 中右键项目 → “属性” → “生成” → “高级” → “语言版本”,此处修改会写回 .csproj,但仅对当前项目有效
接口里写方法体时哪些修饰符能用、哪些会炸
接口成员默认 public,但默认方法是个例外:C# 8+ 允许显式写 public,且推荐写;其他修饰符一律禁止。
- ✅ 合法:
public void Log(string m) { ... }或void Log(string m) { ... }(省略public也行,但易混淆) - ❌ 报 CS0106:
private void Log(...)、internal void Log(...)、protected void Log(...) - ❌ 报 CS0501(抽象方法不能有实现):
abstract void Log(...)+ 方法体 - ❌ 报 CS8702(接口中不允许 virtual/override/sealed):
virtual void Log(...)、override void Log(...)
注意:Java 的 default 关键字在 C# 接口中完全无效,写了就编译失败。
为什么重写默认方法必须加 public override
接口默认方法不是虚方法,但 C# 强制要求重写时走 override 路径——这是类型系统设计决定的,不是语法糖。
- 不加
override→ 编译错误 CS0506:“无法重写继承的成员,因为它不是虚成员” - 用
new隐藏 → 编译通过,但调用行为不可靠:通过接口变量调用走默认实现,通过类变量调用才走 new 版本,极易引发逻辑错乱 - 必须显式写
public override:因为接口方法本身无访问修饰符上下文,override必须补全可访问性 - 若类已从基类继承同签名方法(比如抽象基类实现了
ILogger),则默认接口方法会被完全屏蔽,不会参与重写链
多接口同名默认方法冲突时怎么破
当一个类同时实现 IA 和 IB,而两者都有 void Save() 默认实现,编译器拒绝“猜”你想要哪个。
- 必须在实现类中显式提供
public override void Save(),否则编译失败 - 可在重写方法内用
IA.base.Save()或IB.base.Save()显式调用任一接口的默认逻辑(C# 8+ 支持) - 不能只调用其中一个还留另一个“悬空”:显式实现后,所有通过该类实例或任一接口变量调用
Save()都走这个统一重写体 - 没有类似 Java 的
InterfaceName.super.method()语法;C# 只支持InterfaceName.base.Method()
真正容易被忽略的是:默认方法体内无法访问实现类的私有字段或 this 的完整运行时类型——它看起来像实例方法,实则没有真正的 this 实例上下文,所有对实现类成员的访问都受限于接口可见面。











