十三、接口(Interfaces)
CLR #接口
✅ 第13章:接口(Interfaces)
📌 一、接口的本质与作用
- 接口是 行为合约,定义方法但不实现。
- CLR 支持多接口继承,但不支持多类继承。
- 接口可看作是一种“受控多继承机制”。
📘 接口在 CLR 中的表现:
- 接口方法编译为
virtual,通过vtable或interface dispatch map调用 - 接口在 CLR 中是独立的类型定义(
InterfaceDef)
📌 二、定义与继承接口
public interface ILogger
{
void Log(string message);
}
public class ConsoleLogger : ILogger
{
public void Log(string message) => Console.WriteLine(message);
}
✅ 可继承多个接口:
public interface IReadable { void Read(); }
public interface IWritable { void Write(); }
public class FileIO : IReadable, IWritable { ... }
📌 三、隐式 vs 显式 接口实现
✅ 隐式实现
- 实现的方法是 公共(public) 的
- 可通过类对象直接访问接口方法
public class Logger : ILogger
{
public void Log(string message) => Console.WriteLine(message);
}
✅ 显式实现
- 方法只能通过接口引用访问
- 用于 避免命名冲突或隐藏接口方法
public class Logger : ILogger
{
void ILogger.Log(string message) => Console.WriteLine("Explicit: " + message);
}
ILogger log = new Logger();
log.Log("Hello"); // OK
Logger obj = new Logger();
// obj.Log("Hello"); // ❌ 编译错误
✅ 显式实现的主要作用:
-
解决多个接口方法重名冲突
interface IA { void Print(); } interface IB { void Print(); } class C : IA, IB { void IA.Print() => Console.WriteLine("A"); void IB.Print() => Console.WriteLine("B"); } -
封装行为:防止外部通过类直接访问接口方法,隐藏实现细节
public class FileLogger : ILogger { void ILogger.Log(string msg) => File.WriteAllText("log.txt", msg); } -
增强类型安全性:通过接口控制访问范围,防止误调用
🔍 CLR 机制层面差异
- 隐式实现:编译器将方法标记为
public,属于类的 vtable - 显式实现:方法命名为
InterfaceName.MethodName,不在类的默认方法集中
📌 四、泛型接口与约束
public interface IRepository<T>
{
T GetById(int id);
}
泛型接口可用于构建强类型服务层
- 可添加约束:
public class Repository<T> where T : IEntity { ... }
📌 五、多个接口含相同签名的方法
interface IA { void Print(); }
interface IB { void Print(); }
class X : IA, IB
{
void IA.Print() => Console.WriteLine("A");
void IB.Print() => Console.WriteLine("B");
}
✅ 用显式实现来避免冲突,提高编译期类型安全性。
📊 Mermaid 图:接口继承与实现关系
classDiagram
ILogger <|-- ConsoleLogger
<<Interface>> ILogger
class ILogger {
+log(message: string): void
}
class ConsoleLogger {
+log(message: string): void
}
📌 六、接口 vs 抽象类设计比较
能继承就继承(IS-A),能组合就用接口(CAN-DO)
基类 or接口
| 原则 | 说明 |
|---|---|
| IS-A 关系 | 如果是“属于某种类型”(如 Button 属于 Control),使用基类 |
| CAN-DO 关系 | 如果是“能做某种事”(如对象能排序、能转型),使用接口 |
| 维度 | 接口(interface) | 抽象类(abstract) |
|---|---|---|
| 多继承支持 | ✅ 支持多个接口 | ❌ 仅支持单一基类 |
| 字段 | ❌ 不支持 | ✅ 支持字段/属性/构造函数 |
| 版本兼容性 | 差(加方法会破坏实现) | 高(可添加默认实现) |
| 默认实现支持(C# 8+) | ✅(有限制) | ✅ |
| 适用场景 | 横向扩展(行为) | 纵向继承(模板) |
🧠 面试题
1️⃣ 接口能包含字段或构造函数吗?
❌ 不可以。接口仅定义行为(方法/属性)合约,不定义数据或构造。
2️⃣ 显式接口实现的好处?
✅ 避免命名冲突、隐藏不必要方法、提高封装性。
3️⃣ 接口方法能是 static 吗?
❌ 不行。接口的方法是实例级别,由实现类提供逻辑(C# 8+ 可以定义静态接口成员,但使用场景有限)。
4️⃣ 接口多继承如何解决方法冲突?
✅ 通过显式实现选择调用路径。接口方法签名冲突由实现者明确处理。
5️⃣ 使用接口 vs 抽象类的权衡?
- 如果你需要组合多个不相关的行为 → 接口更适合
- 如果你希望提供默认实现/模板 → 抽象类更合理
✅ 总结表格
| 核心点 | 概述 |
|---|---|
| 接口定义 | 只定义方法签名,无实现 |
| 隐式 vs 显式实现 | 显式可隐藏接口成员 |
| 泛型接口 | 支持强类型扩展 |
| 多接口冲突 | 可用显式分开实现 |
| 抽象类 vs 接口 | 一个用于继承结构,一个用于组合行为 |
点赞鼓励下,(づ ̄3 ̄)づ╭❤~
作者:世纪末的魔术师
出处:https://www.cnblogs.com/Firepad-magic/
Unity最受欢迎插件推荐:点击查看
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

浙公网安备 33010602011771号