十三、接口(Interfaces)

CLR #接口

✅ 第13章:接口(Interfaces)


📌 一、接口的本质与作用

  • 接口是 行为合约,定义方法但不实现。
  • CLR 支持多接口继承,但不支持多类继承。
  • 接口可看作是一种“受控多继承机制”。

📘 接口在 CLR 中的表现:

  • 接口方法编译为 virtual,通过 vtableinterface 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"); // ❌ 编译错误

✅ 显式实现的主要作用:

  1. 解决多个接口方法重名冲突

    interface IA { void Print(); }
    interface IB { void Print(); }
    
    class C : IA, IB {
        void IA.Print() => Console.WriteLine("A");
        void IB.Print() => Console.WriteLine("B");
    }
    
  2. 封装行为:防止外部通过类直接访问接口方法,隐藏实现细节

    public class FileLogger : ILogger {
        void ILogger.Log(string msg) => File.WriteAllText("log.txt", msg);
    }
    
  3. 增强类型安全性:通过接口控制访问范围,防止误调用


🔍 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 接口 一个用于继承结构,一个用于组合行为
posted @ 2025-08-26 10:06  世纪末の魔术师  阅读(9)  评论(0)    收藏  举报