接口与抽象类
翻译整理自 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。