15、接口(C#)
15.1 什么是接口
接口是指定一组函数成员而不实现它们的引用类型。所以只能类和结构实现接口。
15.2 声明接口
- 接口声明不能包含以下成员
- 数据成员
- 静态成员
- 接口声明只能包含以下类型的费静态成员函数声明:
- 方法
- 事件
- 索引器
- 属性
- 这些函数成员的声明不能包含任何实现代码,而在每一个成员声明的主体后必须使用分号;
- 按照惯例接口的名称必须从大写的I开始
- 与类和结构一样,接口声明还可以分隔成分部接口声明,这是在第6章的“分部类和分布结构”部分提到的。
- 接口声明可以有任何访问修饰符public,private,protected,internal。
- 接口的成员是隐式public的,不允许有任何访问修饰符,包括public
15.3 实现接口
只有类和结构才能实现接口。如Sort示例所示,要实现接口,类或者结构必须:
- 在基类列表中包括接口名称;
- 为每一个接口成员提供实现。
- 如果类实现接口,他必须实现接口的所有成员;
- 如果类从基类继承并实现了接口,基类列表中的基类名称必须放在所有接口之前:
15.4 接口是引用类型
接口不仅仅是类或者结构要实现的成员列表。他是一个引用类型。
我们不能直接通过类对象的成员访问接口。然而我们可以通过把类对象引用强制转换为接口类型来获取指向接口的引用。一旦有了接口引用。我们就可以使用点号来调用接口的方法。
15.5 接口和as运算符
- 如果类实现了接口,表达式返回指向接口的引用;
- 如果类没有实现了接口,表达式返回null而不是抛出异常;
15.6 实现多个接口
类或者结构可以实现任意数量的借口。
所有实现的接口必须列在基类列表中并且以逗号分隔开(如果有基类,则在其后);
15.7 实现具有重复成员的接口
由于类可以实现任意数量的接口,有可能有两个或者多个接口成员都有相同的签名和返回类型。编译器如何处理这样的情况呢?
答案如下:一个类实现了多个接口,并且其中的一些接口有相同的签名和返回值类型的成员,那么类可以实现单个成员来满足所有包含重复成员的接口。
15.8 多个接口的引用
我们已经在之前的内容中知道了接口是引用类型,并且可以通过将对象引用强制转换为接口类型的引用,来获取一个指向接口的引用,如果类实现了多个接口,我们可以获取没一个接口的独立引用。
- 通过类对象;
- 通过指向IIfc1接口的引用。
- 通过指向IIfc2接口的引用
15.9 派生类作为实现
实现接口的类可以从它的基类集成实现的代码。
- IIfc1是一个具有PrintOut方法成员的接口;
- MyBaseClass包含了一个叫做PrintOut的3方法,它和IIfc1的方法相匹配
- Derived类有一个空的声明主体,但它派生自MyBaseClass,并在基类列表中包含了IIfc1.
- 即使Derived的声明主体是空的,基类中的代码还是能够满足实现接口方法的需求。
15.10 显示接口成员实现
- 与所有接口实现相似,位于实现接口的类或结构中;
- 它使用限定接口名称来声明,有接口名称和成员以及他们中间的点分隔符号构成。
如果显示接口成员的实现,类级别的实现是允许的,但不是不需的。显示实现了满足了类或结构必须实现的方法。因此,我们可以有如下3种实现场景。
- 类级别实现
- 显示接口成员实现
- 类级别和显示接口成员实现
访问显示接口成员实现
显示接口成员实现只可以通过指向接口引用来访问。也就是说,其他的类成员都不可以直接访问它们。
即使是在本类中的其他方法也不可以使用this直接访问:
这个限制对继承产生了重要影响。由于其他类成员不能直接访问显示接口成员实现,衍生类的成员也不能直接访问它们。他们必须总是通过接口的引用来访问。
15.11 接口可以继承接口
接口实现可以从基类被继承,而接口本身也可以从一个或多个接口继承。
要指定某个接口继承其他接口,应在接口声明中把基接口以逗号分隔的列表形式放在接口名称的冒号之后。
与类不同,它在基类列表中只能有一个类名,而接口可以在基接口中有任意多个接口。
列表中的接口本身可以继承其他接口。
结果接口包含它声明的所有接口何所有基类成员。
15.12 不同类实现一个接口的示例;