第12章 接口

接口定义了一份契约,实现了接口的类或结构就意味着遵守接口定义的契约。接口只允许包含方法、属性、索引器和事件的签名,请注意,这里只允许包含签名,而不能包含实现。另外,接口不能包含常量、字段、运算符、实例构造函数、析构函数以及任何静态成员。

由于接口中不包含成员实现,因此接口中定义的成员必须在实现该接口的类或结构中提供成员实现。因此,一个接口的不同实现类可以有多个不同的实现方式。因此,当外界依赖的是接口,而不是实现类的时候,可以轻易地调换实现该接口的实现类,而无须改变依赖于该接口的代码,这就是业界为什么推崇“面向接口编程”的原因。

实现类不能选择实现接口中的某些成员,而不去实现另外一些成员,它必须全部、毫无保留地实现接口的所有成员,无论是方法、属性、索引器还是事件。除此以外,实现类还可以定义自己的成员,由于这些成员没有在接口中进行定义,因此当通过接口的引用进行访问的时候,这些成员将不可见。

那么,我们来看看接口具有哪些特点:

❑接口可以从一个或多个基接口继承,一个类或结构也可以实现多个接口,如图12-1所示;

第12章 接口 - 图1

图 12-1 接口可以从多个基接口继承

❑接口只包含方法、属性、索引器和事件的签名,不能包含实现;

❑接口不能包含字段、常量、运算符、实例构造函数、析构函数以及任何静态成员;

❑接口的成员默认是公共的(public),且不可以再显式声明为public,否则将产生编译异常:修饰符"public"对该项无效。

❑接口不能被实例化,从接口类型编译后生成的CIL代码可以看到,接口的声明是抽象(abstract)的,如图12-2所示;

第12章 接口 - 图2

图 12-2 接口的IL结构

❑实现接口的类必须实现接口的所有成员,不管是方法、属性、索引器还是事件。

12.1 定义接口

首先,我们要学习如何定义一个接口。接口的定义非常类似于类的定义,只是把class关键字换成interface关键字,然而,接口的成员只包含签名,不包含内容,且不能包含任何访问修饰符(默认为public级别),需要说明的是必须以分号结尾,语法如图12-3所示。

第12章 接口 - 图3

图 12-3 接口的定义

下面,我们对接口定义中的几个关键部分进行说明,如表12-1所示。

第12章 接口 - 图4

我们知道,接口中可以包含方法、属性、索引器和事件的签名,不包含实现,我们接下来就通过一段示例代码来展示这些合法的成员是如何在接口中进行声明的,如代码清单12-1所示。

代码清单12-1 接口成员示例


interface Sample

{

void SayHello();//方法签名

int Age{get;set;}//属性签名

EventHandler SizeChanged();//事件签名

int this[int index]{get;set;}//索引器签名

}


在上述代码中,我们分别定义了一个方法,一个属性,一个事件,以及一个索引器。其中,属性的和索引器的签名必须包含完整的get和set访问器,这点需要特别注意。

接下来,我们来学习如何声明和实现接口。