第五节实现接口
显式实现接口成员
为了实现接口类可以定义显式接口成员执行体(Explicit interface member implementations)显式接口成员执行体可以是一个方法一个属性一个事件或者是一个索引指示器的定义定义与该成员对应的全权名应保持一致
using System ;
interface ICloneable
{
object Clone( ) ;
}
interface IComparable
{
int CompareTo(object other) ;
}
class ListEntry: ICloneable IComparable
{
object ICloneableClone( ) {…}
int IComparableCompareTo(object other) {…}
}
上面的代码中ICloneableClone 和IComparableCompareTo 就是显式接口成员执行体
说明
不能在方法调用属性访问以及索引指示器访问中通过全权名访问显式接口成员执行体事实上显式接口成员执行体只能通过接口的实例仅仅引用接口的成员名称来访问
显式接口成员执行体不能使用任何访问限制符也不能加上abstract virtual override或static 修饰符
显式接口成员执行体和其他成员有着不同的访问方式因为不能在方法调用属性访问以及索引指示器访问中通过全权名访问显式接口成员执行体在某种意义上是私有的但它们又可以通过接口的实例访问也具有一定的公有性质
只有类在定义时把接口名写在了基类列表中而且类中定义的全权名类型和返回类型都与显式接口成员执行体完全一致时显式接口成员执行体才是有效的例如
class Shape: ICloneable
{
object ICloneableClone( ) {…}
int IComparableCompareTo(object other) {…}
}
使用显式接口成员执行体通常有两个目的
因为显式接口成员执行体不能通过类的实例进行访问这就可以从公有接口中把接口的实现部分单独分离开如果一个类只在内部使用该接口而类的使用者不会直接使用到该接口这种显式接口成员执行体就可以起到作用
显式接口成员执行体避免了接口成员之间因为同名而发生混淆如果一个类希望对名称和返回类型相同的接口成员采用不同的实现方式这就必须要使用到显式接口成员执行体如果没有显式接口成员执行体那么对于名称和返回类型不同的接口成员类也无法进行实现
下面的定义是无效的因为Shape 定义时基类列表中没有出现接口IComparable
class Shape: ICloneable
{
object ICloneableClone( ) {…}
}
class Ellipse: Shape
{
object ICloneableClone( ) {…}
}
在Ellipse 中定义ICloneableClone是错误的因为Ellipse即使隐式地实现了接口ICloneableICloneable仍然没有显式地出现在Ellipse定义的基类列表中
接口成员的全权名必须对应在接口中定义的成员如下面的例子中Paint的显式接口成员执行体必须写成IControlPaint
using System ;
interface IControl
{
void Paint( ) ;
}
interface ITextBox: IControl
{
void SetText(string text) ;
}
class TextBox: ITextBox
{
void IControlPaint( ) {…}
void ITextBoxSetText(string text) {…}
}
实现接口的类可以显式实现该接口的成员当显式实现某成员时不能通过类实例访问该成员而只能通过该接口的实例访问该成员显式接口实现还允许程序员继承共享相同成员名的两个接口并为每个接口成员提供一个单独的实现
下面例子中同时以公制单位和英制单位显示框的尺寸Box类继承 IEnglishDimensions和 IMetricDimensions两个接口它们表示不同的度量衡系统两个接口有相同的成员名 Length 和 Width
程序清单 DemonInterfacecs
interface IEnglishDimensions
{
float Length ( ) ;
float Width ( ) ;
}
interface IMetricDimensions
{
float Length ( ) ;
float Width ( ) ;
}
class Box : IEnglishDimensions IMetricDimensions
{
float lengthInches ;
float widthInches ;
public Box(float length float width)
{
lengthInches = length ;
widthInches = width ;
}
float IEnglishDimensionsLength( )
{
return lengthInches ;
}
float IEnglishDimensionsWidth( )
{
return widthInches ;
}
float IMetricDimensionsLength( )
{
return lengthInches * f ;
}
float IMetricDimensionsWidth( )
{
return widthInches * f ;
}
public static void Main( )
{
//定义一个实类对象 myBox:
Box myBox = new Box(f f);
// 定义一个接口 eDimensions::
IEnglishDimensions eDimensions = (IEnglishDimensions) myBox;
IMetricDimensions mDimensions = (IMetricDimensions) myBox;
// 输出:
SystemConsoleWriteLine( Length(in): {} eDimensionsLength( ));
SystemConsoleWriteLine( Width (in): {} eDimensionsWidth( ));
SystemConsoleWriteLine( Length(cm): {} mDimensionsLength( ));
SystemConsoleWriteLine( Width (cm): {} mDimensionsWidth( ));
}
}
输出Length(in): Width (in): Length(cm): Width (cm):
代码讨论如果希望默认度量采用英制单位请正常实现 Length 和 Width 这两个方法并从 IMetricDimensions 接口显式实现 Length 和 Width 方法
public float Length( )
{
return lengthInches ;
}
public float Width( )
{
return widthInches;
}
float IMetricDimensionsLength( )
{
return lengthInches * f ;
}
float IMetricDimensionsWidth( )
{
return widthInches * f ;
}
这种情况下可以从类实例访问英制单位而从接口实例访问公制单位
SystemConsoleWriteLine(Length(in): {} myBoxLength( )) ;
SystemConsoleWriteLine(Width (in): {} myBoxWidth( )) ;
SystemConsoleWriteLine(Length(cm): {} mDimensionsLength( )) ;
SystemConsoleWriteLine(Width (cm): {} mDimensionsWidth( )) ;