C# 接口(Interface)
定义、多实现、默认实现、显式实现、以及接口隔离。
定义与实现
interface IShape
{
double Area();
double Perimeter();
string Name { get; } // 接口可以有属性
}
class Circle : IShape
{
public double Radius { get; set; }
public string Name => "圆";
public double Area() => Math.PI * Radius * Radius;
public double Perimeter() => 2 * Math.PI * Radius;
}
class Square : IShape
{
public double Side { get; set; }
public string Name => "正方形";
public double Area() => Side * Side;
public double Perimeter() => 4 * Side;
}
IShape[] shapes = { new Circle { Radius = 1 }, new Square { Side = 2 } };
foreach (var s in shapes)
{
Console.WriteLine($"{s.Name} 面积 {s.Area():F2} 周长 {s.Perimeter():F2}");
}圆 面积 3.14 周长 6.28
正方形 面积 4.00 周长 8.00Interface names start with I by convention. An interface declares capability only: IShape neither knows nor cares whether you are a circle or a square.
多实现
interface IReadable { string Read(); }
interface IWritable { void Write(string data); }
// 一个类实现多个接口
class FileStore : IReadable, IWritable
{
private string _data = "";
public string Read() => _data;
public void Write(string data) => _data = data;
}
IReadable r = new FileStore();
IWritable w = (IWritable)r;
w.Write("hello");
Console.WriteLine(r.Read());
var store = new FileStore();
Console.WriteLine(store is IReadable && store is IWritable);hello
True默认实现
interface IGreeter
{
string Name { get; }
// C# 8:接口可以有默认实现
string Greet() => $"你好,我是 {Name}";
string Loud() => Greet().ToUpper();
}
class Person : IGreeter
{
public string Name => "张三";
}
class Robot : IGreeter
{
public string Name => "R2";
public string Greet() => "哔哔";
}
IGreeter a = new Person();
IGreeter b = new Robot();
Console.WriteLine(a.Greet());
Console.WriteLine(a.Loud());
Console.WriteLine(b.Greet());你好,我是 张三
你好,我是 张三
哔哔Default implementations let an interface add a method without breaking implementers. Caveat: they are only reachable through an interface reference — new Person().Greet() does not compile.
显式实现
interface IA { string Hello(); }
interface IB { string Hello(); }
class Both : IA, IB
{
// 显式实现:只能通过对应接口调用
string IA.Hello() => "来自 IA";
string IB.Hello() => "来自 IB";
// 也可以再给一个公开版本
public string Hello() => "公开版本";
}
var b = new Both();
Console.WriteLine(b.Hello());
Console.WriteLine(((IA)b).Hello());
Console.WriteLine(((IB)b).Hello());公开版本
来自 IA
来自 IBExplicit implementation is the only way out when two interfaces share a method name. Those members are not public, so b.Hello() cannot see them — cast to the interface.
接口 vs 抽象类
| Aspect | Interface | Abstract class |
|---|---|---|
| 多继承 | 可以多个 | 只能一个 |
| 字段 | 不能有实例字段 | 可以有 |
| 构造 | 不能有构造函数 | 可以有 |
| 默认实现 | C# 8+ 可以 | 可以 |
| 语义 | 「能做什么」 | 「是什么」 |
| 适用 | 跨不相关的类型共享能力 | 相关的类型共享实现 |
IDisposable, IComparable); abstract classes for state machines with shared code (Stream, DbConnection).常用 BCL 接口
class Item : IComparable<Item>, IEquatable<Item>
{
public string Name { get; set; } = "";
public int Price { get; set; }
// 排序用
public int CompareTo(Item? other) => Price.CompareTo(other?.Price ?? 0);
// 相等用
public bool Equals(Item? other) => other is not null && Name == other.Name && Price == other.Price;
public override bool Equals(object? o) => Equals(o as Item);
public override int GetHashCode() => HashCode.Combine(Name, Price);
}
var items = new List<Item>
{
new() { Name = "b", Price = 20 },
new() { Name = "a", Price = 10 },
};
items.Sort();
Console.WriteLine(string.Join(",", items.Select(i => i.Name)));a,bImplement IComparable<T> and List.Sort() works; implement IEnumerable<T> and foreach plus LINQ work. In C#, joining the ecosystem means implementing these standard interfaces.
定义与实现
interface IShape
{
double Area();
double Perimeter();
string Name { get; } // 接口可以有属性
}
class Circle : IShape
{
public double Radius { get; set; }
public string Name => "圆";
public double Area() => Math.PI * Radius * Radius;
public double Perimeter() => 2 * Math.PI * Radius;
}
class Square : IShape
{
public double Side { get; set; }
public string Name => "正方形";
public double Area() => Side * Side;
public double Perimeter() => 4 * Side;
}
IShape[] shapes = { new Circle { Radius = 1 }, new Square { Side = 2 } };
foreach (var s in shapes)
{
Console.WriteLine($"{s.Name} 面积 {s.Area():F2} 周长 {s.Perimeter():F2}");
}圆 面积 3.14 周长 6.28
正方形 面积 4.00 周长 8.00接口命名惯例是 I 开头。接口只声明能力,不关心实现——IShape 不知道也不在乎你是圆还是正方形。
多实现
interface IReadable { string Read(); }
interface IWritable { void Write(string data); }
// 一个类实现多个接口
class FileStore : IReadable, IWritable
{
private string _data = "";
public string Read() => _data;
public void Write(string data) => _data = data;
}
IReadable r = new FileStore();
IWritable w = (IWritable)r;
w.Write("hello");
Console.WriteLine(r.Read());
var store = new FileStore();
Console.WriteLine(store is IReadable && store is IWritable);hello
True默认实现
interface IGreeter
{
string Name { get; }
// C# 8:接口可以有默认实现
string Greet() => $"你好,我是 {Name}";
string Loud() => Greet().ToUpper();
}
class Person : IGreeter
{
public string Name => "张三";
}
class Robot : IGreeter
{
public string Name => "R2";
public string Greet() => "哔哔";
}
IGreeter a = new Person();
IGreeter b = new Robot();
Console.WriteLine(a.Greet());
Console.WriteLine(a.Loud());
Console.WriteLine(b.Greet());你好,我是 张三
你好,我是 张三
哔哔默认实现让接口能向后兼容地加方法:老实现类不用改就能编译。但要注意——默认实现只能通过接口引用调用,new Person().Greet() 是编译错误。
显式实现
interface IA { string Hello(); }
interface IB { string Hello(); }
class Both : IA, IB
{
// 显式实现:只能通过对应接口调用
string IA.Hello() => "来自 IA";
string IB.Hello() => "来自 IB";
// 也可以再给一个公开版本
public string Hello() => "公开版本";
}
var b = new Both();
Console.WriteLine(b.Hello());
Console.WriteLine(((IA)b).Hello());
Console.WriteLine(((IB)b).Hello());公开版本
来自 IA
来自 IB两个接口有同名方法时,显式实现是唯一的解。显式实现的成员不是 public,b.Hello() 调不到——必须转成对应接口。
接口 vs 抽象类
| 对比项 | 接口 | 抽象类 |
|---|---|---|
| 多继承 | 可以多个 | 只能一个 |
| 字段 | 不能有实例字段 | 可以有 |
| 构造 | 不能有构造函数 | 可以有 |
| 默认实现 | C# 8+ 可以 | 可以 |
| 语义 | 「能做什么」 | 「是什么」 |
| 适用 | 跨不相关的类型共享能力 | 相关的类型共享实现 |
IDisposable、IComparable 这种「任何类型都可能具备」的能力用接口;Stream、DbConnection 这种「有共享实现的状态机」用抽象类。常用 BCL 接口
class Item : IComparable<Item>, IEquatable<Item>
{
public string Name { get; set; } = "";
public int Price { get; set; }
// 排序用
public int CompareTo(Item? other) => Price.CompareTo(other?.Price ?? 0);
// 相等用
public bool Equals(Item? other) => other is not null && Name == other.Name && Price == other.Price;
public override bool Equals(object? o) => Equals(o as Item);
public override int GetHashCode() => HashCode.Combine(Name, Price);
}
var items = new List<Item>
{
new() { Name = "b", Price = 20 },
new() { Name = "a", Price = 10 },
};
items.Sort();
Console.WriteLine(string.Join(",", items.Select(i => i.Name)));a,b实现 IComparable<T> 后 List.Sort() 就能用;实现 IEnumerable<T> 后 foreach 和 LINQ 就能用。C# 里「让类型融入生态」的方式就是实现这些标准接口。