映射接口
类必须为在基类表中列出的所有接口的成员提供具体的实现在类中定位接口成员的实现称之为接口映射(interface mapping )
映射数学上表示一一对应的函数关系接口映射的含义也是一样接口通过类来实现那么对于在接口中定义的每一个成员都应该对应着类的一个成员来为它提供具体的实现
类的成员及其所映射的接口成员之间必须满足下列条件
如果A和B都是成员方法那么A和B的名称类型形参表(包括参数个数和每一个参数的类型)都应该是一致的
如果A和B都是属性那么A和B的名称类型应当一致而且A和B的访问器也是类似的但如果A不是显式接口成员执行体A允许增加自己的访问器
如果A和B都是时间那么A和B的名称类型应当一致
如果A和B都是索引指示器那么A和B的类型形参表(包括参数个数和每一个参数的类型)应当一致而且A和B的访问器也是类似的但如果A不是显式接口成员执行体A允许增加自己的访问器
那么对于一个接口成员怎样确定由哪一个类的成员来实现呢?即一个接口成员映射的是哪一个类的成员?在这里我们叙述一下接口映射的过程假设类C实现了一个接口IInterfaceMember是接口IInterface中的一个成员在定位由谁来实现接口成员Member即Member的映射过程是这样的
如果C中存在着一个显式接口成员执行体该执行体与接口IInterface 及其成员Member相对应则由它来实现Member 成员
如果条件()不满足且C中存在着一个非静态的公有成员该成员与接口成员Member相对应则由它来实现Member 成员
如果上述条件仍不满足则在类C定义的基类列表中寻找一个C 的基类D用D来代替C
重复步骤 遍历C的所有直接基类和非直接基类直到找到一个满足条件的类的成员
如果仍然没有找到则报告错误
下面是一个调用基类方法来实现接口成员的例子类Class 实现了接口Interface类Class 的基类Class 的成员也参与了接口的映射也就是说类Class 在对接口Interface进行实现时使用了类Class提供的成员方法F来实现接口Interface的成员方法F
interface Interface
{
void F( ) ;
}
class Class
{
public void F( ) { }
public void G( ) { }
}
class Class: Class Interface
{
new public void G( ) {}
}
注意接口的成员包括它自己定义的成员而且包括该接口所有父接口定义的成员在接口映射时不仅要对接口定义体中显式定义的所有成员进行映射而且要对隐式地从父接口那里继承来的所有接口成员进行映射
在进行接口映射时还要注意下面两点
在决定由类中的哪个成员来实现接口成员时类中显式说明的接口成员比其它成员优先实现
使用Privateprotected和static修饰符的成员不能参与实现接口映射例如
interface ICloneable
{
object Clone( ) ;
}
class C: ICloneable
{
object ICloneableClone( ) {…}
public object Clone( ) {…}
}
例子中成员ICloneableClone 称为接口ICloneable 的成员Clone 的实现者因为它是显式说明的接口成员比其它成员有着更高的优先权
如果一个类实现了两个或两个以上名字类型和参数类型都相同的接口那么类中的一个成员就可能实现所有这些接口成员
interface IControl
{
void Paint( ) ;
}
interface IForm
{
void Paint( ) ;
}
class Page: IControl IForm
{
public void Paint( ) {…}
}
这里接口IControl和IForm的方法Paint都映射到了类Page中的Paint方法当然也可以分别用显式的接口成员分别实现这两个方法
interface IControl
{
void Paint( ) ;
}
interface IForm
{
void Paint( ) ;
}
class Page: IControl IForm
{
public void IControlPaint( )
{
//具体的接口实现代码
}
public void IFormPaint( )
{
//具体的接口实现代码
}
}
上面的两种写法都是正确的但是如果接口成员在继承中覆盖了父接口的成员那么对该接口成员的实现就可能必须映射到显式接口成员执行体看下面的例子
interface IBase
{
int P { get; }
}
interface IDerived: IBase
{
new int P( ) ;
}
接口IDerived从接口IBase中继承这时接口IDerived 的成员方法覆盖了父接口的成员方法因为这时存在着同名的两个接口成员那么对这两个接口成员的实现如果不采用显式接口成员执行体编译器将无法分辨接口映射所以如果某个类要实现接口IDerived在类中必须至少定义一个显式接口成员执行体采用下面这些写法都是合理的
//一对两个接口成员都采用显式接口成员执行体来实现
lass C: IDerived
{
int IBaseP
get
{ //具体的接口实现代码 }
int IDerivedP( )
{//具体的接口实现代码 }
}
//二对Ibase 的接口成员采用显式接口成员执行体来实现
class C: IDerived
{
int IBaseP
get {//具体的接口实现代码}
public int P( ){//具体的接口实现代码 }
}
//三对IDerived 的接口成员采用显式接口成员执行体来实现
class C: IDerived
{
public int P
get {//具体的接口实现代码}
int IDerivedP( ){//具体的接口实现代码}
}
另一种情况是如果一个类实现了多个接口这些接口又拥有同一个父接口这个父接口只允许被实现一次
using System ;
interface IControl
{
void Paint( ) ;
interface ITextBox: IControl
{
void SetText(string text) ;
}
interface IListBox: IControl
{
void SetItems(string[] items) ;
}
class ComboBox: IControl ITextBox IListBox
{
void IControlPaint( ) {…}
void ITextBoxSetText(string text) {…}
void IListBoxSetItems(string[] items) {…}
}
}
上面的例子中类ComboBox实现了三个接口IControlITextBox和IListBox如果认为ComboBox不仅实现了IControl接口而且在实现ITextBox和IListBox的同时又分别实现了它们的父接口IControl实际上对接口ITextBox 和IListBox 的实现分享了对接口IControl 的实现
我们对C#的接口有了较全面的认识基本掌握了怎样应用C#的接口编程但事实上C#的不仅仅应用于NET平台它同样支持以前的COM可以实现COM类到NET类的转换如C#调用API欲了解这方面的知识请看下一节接口转换