C# 接口(Interface)

定义、多实现、默认实现、显式实现、以及接口隔离。

Intermediate
Key Points类只能继承一个父类,但能实现任意多个接口。

定义与实现

C#
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}");
}
Output
圆 面积 3.14 周长 6.28
正方形 面积 4.00 周长 8.00

Interface names start with I by convention. An interface declares capability only: IShape neither knows nor cares whether you are a circle or a square.

多实现

C#
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);
Output
hello
True

默认实现

C#
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());
Output
你好,我是 张三
你好,我是 张三
哔哔

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.

显式实现

C#
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());
Output
公开版本
来自 IA
来自 IB

Explicit 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 抽象类

AspectInterfaceAbstract class
多继承可以多个只能一个
字段不能有实例字段可以有
构造不能有构造函数可以有
默认实现C# 8+ 可以可以
语义「能做什么」「是什么」
适用跨不相关的类型共享能力相关的类型共享实现
The rule: interfaces describe capability, abstract classes provide implementation. Use interfaces for abilities any type might have (IDisposable, IComparable); abstract classes for state machines with shared code (Stream, DbConnection).

常用 BCL 接口

C#
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)));
Output
a,b

Implement IComparable<T> and List.Sort() works; implement IEnumerable<T> and foreach plus LINQ work. In C#, joining the ecosystem means implementing these standard interfaces.

Friends & Partners