C# 接口(interface)的定义、实现、显式和默认实现、静态成员
概述
接口定义一个协定(contract)。 任何 class、record、struct 要实现这个协定,必须为该接口的所有成员提供实现。
C# 里,class 不能从多个 class 继承(multiple inheritance),但可以实现多个接口。
struct 不能从 class 或 struct 继承,但可以实现接口。
随着 C# 版本的更新,接口也逐渐增加了一些新特性。
本文中的接口是对当前版本 C# 13(.NET 9)而言,有些功能在老旧版本中是没有的。
接口可以包含方法(methods)、属性(properties)、事件(events)、索引器(indexers)。
接口可以包含静态(static)方法,默认实现成员(default implementation)
接口还可以包含静态构造方法(static constructors)、静态字段(static fields)、常量(constants)、运算符(operators)。
接口不能包含实例字段,实例构造方法,终结器(finalizers)。
接口成员默认是 public,但可以声明为 protected, internal, private, protected internal, 或 private protected。 声明为 private 的成员必须有默认实现。
接口的定义与实现
下面例子来自 .NET 的 System.IEquatable<T> 接口。
System.IEquatable<T> 的定义:
实现 System.IEquatable<T> 的一个例子:
接口的显式实现
(a)多个接口有相同的成员,如果需要,可以为它们提供同一个实现。
比如下面这个例子,接口 IControl 和 接口 ISurface 都有同一个方法 Paint。 类 SampleClass 实现这两个接口,其中方法 Paint 同时实现了接口 IControl 和 接口 ISurface 的方法 Paint。
代码片段如下:
(b)多个接口有相同名称的成员,但是类型不一样,则需要把其中一些作显式实现,加以区分。
比如下面这个例子,P 在接口 ILeft 中是一个属性,在接口 IRight 中是一个方法。类 Middle 实现时,必须把其中一个作显式实现,否则发生冲突,编译错误。:
代码片段如下:
(c)多个接口有相同的成员,但需要实现不同的功能,则可以采用显式实现。
比如下面这个例子,定义和尺寸有关的两个接口,一个使用公制,另一个使用英制,都有 Length() 和 Width() 两个方法。 因为方法名有同名,又必须提供不同功能,所以需要显式实现。
代码片段如下:
接口的默认实现
在 C# 8.0 及更高版本中,接口可以包含成员的默认实现。
允许开发者为接口成员提供实现,同时仍然保持接口的灵活性。可用于向后兼容等。
这里是一个默认实现的例子,代码片段如下:
接口的静态成员
下面例子使用接口静态字段来存放默认实现的参数,配合默认实现,在为接口添加新功能时带来便利。
代码片段如下:
从 C# 11 开始,接口可以包含 static abstract 成员和 static virtual 成员,这是对接口功能的进一步扩展,支撑了 .NET 中的泛型数学(Generic math)。
结束语
接口是.NET中实现抽象和多态的关键机制,对构建可扩展、可维护的应用程序至关重要。
本文简单摘录了 C# 接口的几个功能和要点。