接口与抽象类

翻译整理自 Interfaces 与 Records & Interfaces。

1. 接口定义

public interface IComparable
{
    int CompareTo(object other);
}

public class Person : IComparable
{
    public int Age { get; set; }
    public int CompareTo(object other) => Age - ((Person)other).Age;
}

可多实现:

public class Service : IService, IDisposable, ICloneable
{
    public void Run() { }
    public void Dispose() { }
    public object Clone() => MemberwiseClone();
}

2. 接口属性与默认实现

C# 8+ 支持默认接口方法:

public interface ILogger
{
    void Log(string msg) => Console.WriteLine(msg);
    void Error(string msg) => Log($"[ERR] {msg}");
}

public class ConsoleLogger : ILogger
{
    // 不实现 Log 也能用默认实现
}

new ConsoleLogger().Log("x");

3. 接口与抽象类选择

特性 抽象类 接口
多继承 ❌ 单继承 ✅ 多实现
字段 ✅ ❌(属性可以)
构造函数 ✅ ❌
访问修饰 ✅ 默认 public
默认实现 ✅ C# 8+ 支持

设计原则:抽象类表示"是什么"(is-a),接口表示"能做什么"(can-do)。

4. 接口变体(协变/逆变)

interface IEnumerable<out T> { }         // out 协变
interface IComparer<in T> { }            // in 逆变

IEnumerable<string> strs = new List<string>();
IEnumerable<object> objs = strs;         // OK,协变

IComparer<object> cmp = ...;
IComparer<string> scmp = cmp;            // OK,逆变

5. 接口组合

interface IRead { }
interface IWrite { }
interface IReadWriter : IRead, IWrite { }

class Repo : IReadWriter { }

6. 显式接口实现

public class Box : IComparable
{
    int IComparable.CompareTo(object other) {
        // 只能通过 IComparable 引用调用
    }
}

避免接口方法暴露在主 API 上。

7. 依赖倒置原则

public interface IRepository<T> { T Get(int id); }

public class UserService
{
    private readonly IRepository<User> _repo;
    public UserService(IRepository<User> repo) => _repo = repo;

    public User Get(int id) => _repo.Get(id);
}

8. 常用 .NET 接口

接口 含义
IEquatable<T> Equals(T)
IComparable<T> 比较
IEnumerable<T> 迭代
IDisposable 释放资源
ICloneable 克隆
IFormattable ToString(format)
IConverter<T,U> 转换

9. 实现 IEquatable 与 IComparable

public class Person : IEquatable<Person>, IComparable<Person>
{
    public int Id { get; set; }

    public bool Equals(Person other) => other is not null && Id == other.Id;
    public override bool Equals(object obj) => Equals(obj as Person);
    public override int GetHashCode() => Id;

    public int CompareTo(Person other) => Id.CompareTo(other?.Id);
}

小结

接口是 C# 解耦与依赖注入的基础,配合 record、表达式成员可写出极简 API。