接口定义必须用 interface
关键字,不能有字段和构造函数
接口是契约,只声明行为,不提供实现。C# 中用
interface定义,所有成员默认是
public且不能加访问修饰符;不允许写字段、属性赋值、构造函数或静态成员(C# 8.0+ 允许
static方法但不能有状态)。
interface内只能有方法、属性、事件、索引器的签名,不能有
{} 实现体(C# 8.0+ 支持默认实现,但需显式用 default语义理解) 错误写法:
interface ILogger {
private string _prefix = "App"; // ❌ 编译报错:接口中不能包含字段
public ILogger() { } // ❌ 接口不能有构造函数
}
正确写法:interface ILogger {
void Log(string message);
string Name { get; set; }
}
类实现接口必须用冒号 :
,且显式实现所有成员
一个类用
:后接接口名表示实现,编译器会强制检查是否实现了接口中每个成员。如果漏掉任一方法或属性,编译直接失败,不是运行时报错。 实现时可选择显式实现(
void ILogger.Log(...))或隐式实现(
public void Log(...)),前者仅能通过接口变量调用,后者可通过类实例或接口变量调用 若接口有同名成员(如多个接口都有
Dispose()),显式实现可避免冲突 示例:
class ConsoleLogger : ILogger {
public void Log(string message) {
Console.WriteLine($"[LOG] {message}");
}
<pre class='brush:php;toolbar:false;'>public string Name { get; set; } = "Console";}
一个类可实现多个接口,但只能继承一个基类
C# 不支持多继承,但允许多接口实现——这是组合行为的主要手段。接口之间也可继承,用
:连接,类似类继承语法。 多个接口用逗号分隔:
class Service : IStartable, IStoppable, IDisposable接口继承示例:
interface ILoggable {
void Log(string msg);
}
interface IVerboseLoggable : ILoggable {
void LogVerbose(string detail);
}
实现 IVerboseLoggable的类,必须同时实现
Log和
LogVerbose注意:接口继承不构成“is-a”关系,只是契约叠加,不要滥用继承层次
显式接口实现容易被忽略:调用时需用接口类型变量
显式实现的方法在类实例上调用不了,必须把对象转成接口类型。这个限制常导致新手困惑:“明明写了方法,为什么点不出来?”
显式写法:class FileLogger : ILogger {
void ILogger.Log(string message) {
File.AppendAllText("app.log", $"[{DateTime.Now}] {message}\n");
}
string ILogger.Name { get; set; } = "File";
}
调用方式:var logger = new FileLogger();
// logger.Log("test"); // ❌ 编译错误:找不到 Log 方法
((ILogger)logger).Log("test"); // ✅ 正确
ILogger iLogger = logger; // 隐式转换
iLogger.Log("test"); // ✅ 正确
适用场景:避免类的公共 API 过于臃肿,或实现多个接口时命名冲突
接口本身不占实例内存,但实现类的虚方法表会增加间接调用开销;高频路径慎用接口抽象,尤其是热循环里反复调用
interface方法。真正需要抽象时再引入,别为“设计感”提前套接口。
