接口 - 定义多种类型的行为

接口包含非抽象 classstruct 必须实现的一组相关功能的定义。 接口可以定义 static 方法,此类方法必须具有实现。 接口可为成员定义默认实现。 接口不能声明实例数据,如字段、自动实现的属性或类似属性的事件。

例如,使用接口可以在类中包括来自多个源的行为。 该功能在 C# 中十分重要,因为该语言不支持类的多重继承。 此外,如果要模拟结构的继承,也必须使用接口,因为它们无法实际从另一个结构或类继承。

可使用 interface 关键字定义接口,如以下示例所示。

interface IEquatable<T>
{
    bool Equals(T obj);
}

接口名称必须是有效的 C# 标识符名称。 按照约定,接口名称以大写字母 I 开头。

实现 IEquatable<T> 接口的任何类或结构都必须包含与该接口指定的签名匹配的 Equals 方法的定义。 因此,可以依靠实现 IEquatable<T> 的类型 T 的类来包含 Equals 方法,类的实例可以通过该方法确定它是否等于相同类的另一个实例。

IEquatable<T> 的定义不为 Equals 提供实现。 类或结构可以实现多个接口,但是类只能从单个类继承。

有关抽象类的详细信息,请参阅抽象类、密封类及类成员

接口可以包含实例方法、属性、事件、索引器或这四种成员类型的任意组合。 接口可以包含静态构造函数、字段、常量或运算符。 从 C# 11 开始,非字段接口成员可以是 static abstract。 接口不能包含实例字段、实例构造函数或终结器。 接口成员默认是公共的,可以显式指定可访问性修饰符(如 publicprotectedinternalprivateprotected internalprivate protected)。 private 成员必须有默认实现。

若要实现接口成员,实现类的对应成员必须是公共、非静态,并且具有与接口成员相同的名称和签名。

注意

当接口声明静态成员时,实现该接口的类型也可能声明具有相同签名的静态成员。 它们是不同的,并且由声明成员的类型唯一标识。 在类型中声明的静态成员不会覆盖接口中声明的静态成员。

实现接口的类或结构必须为所有已声明的成员提供实现,而非接口提供的默认实现。 但是,如果基类实现接口,则从基类派生的任何类都会继承该实现。

下面的示例演示 IEquatable<T> 接口的实现。 实现类 Car 必须提供 Equals 方法的实现。

public class Car : IEquatable<Car>
{
    public string? Make { get; set; }
    public string? Model { get; set; }
    public string? Year { get; set; }

    // Implementation of IEquatable<T> interface
    public bool Equals(Car? car)
    {
        return (this.Make, this.Model, this.Year) ==
            (car?.Make, car?.Model, car?.Year);
    }
}

类的属性和索引器可以为接口中定义的属性或索引器定义额外的访问器。 例如,接口可能会声明包含 get 取值函数的属性。 实现此接口的类可以声明包含 getget 取值函数的同一属性。 但是,如果属性或索引器使用显式实现,则访问器必须匹配。 有关显式实现的详细信息,请参阅显式接口实现接口属性

接口可从一个或多个接口继承。 派生接口从其基接口继承成员。 实现派生接口的类必须实现派生接口中的所有成员,包括派生接口的基接口的所有成员。 该类可能会隐式转换为派生接口或任何其基接口。 类可能通过它继承的基类或通过其他接口继承的接口来多次包含某个接口。 但是,类只能提供接口的实现一次,并且仅当类将接口作为类定义的一部分 (class ClassName : InterfaceName) 进行声明时才能提供。 如果由于继承实现接口的基类而继承了接口,则基类会提供接口的成员的实现。 但是,派生类可以重新实现任何虚拟接口成员,而不是使用继承的实现。 当接口声明方法的默认实现时,实现该接口的任何类都会继承该实现(你需要将类实例强制转换为接口类型,才能访问接口成员上的默认实现)。

基类还可以使用虚拟成员实现接口成员。 在这种情况下,派生类可以通过重写虚拟成员来更改接口行为。 有关虚拟成员的详细信息,请参阅多态性

接口摘要

接口具有以下属性:

  • 在 8.0 以前的 C# 版本中,接口类似于只有抽象成员的抽象基类。 实现接口的类或结构必须实现其所有成员。
  • 从 C# 8.0 开始,接口可以定义其部分或全部成员的默认实现。 实现接口的类或结构不一定要实现具有默认实现的成员。 有关详细信息,请参阅默认接口方法
  • 接口无法直接进行实例化。 其成员由实现接口的任何类或结构来实现。
  • 一个类或结构可以实现多个接口。 一个类可以继承一个基类,还可实现一个或多个接口。