大学IT网 - 最懂大学生的IT学习网站! QQ资料交流群:367606806
当前位置:大学IT网 > C#技巧 > C#接口知识大全收藏

C#接口知识大全收藏(6)

关键词:接口收藏知识大全  阅读(3614) 赞(20)

[摘要]接口(interface)用来定义一种程序的协定。实现接口的类或者结构要与接口的定义严格一致。
因为通过外部指派接口成员实现了每个成员,所以用这种方法实现的成员称为外部接口成员。外部接口成员可以只是通过接口来调用。例如,Paint方法中EditBox的实现可以只是通过创建Icontrol接口来调用。


 class Test {
 
  static void Main( ) {
 
   EditBox editbox = new EditBox( );
 
   editbox.Paint( ); //错误: EditBox 没有Paint 事件
 
   IControl control = editbox;
 
   control.Paint( ); // 调用 EditBox的Paint事件
 
  }
 
 }


上例中,类EditBox 从Control 类继承并同时实现了IControl and IDataBound 接口。EditBox 中的Paint 方法来自IControl 接口,Bind 方法来自IDataBound 接口,二者在EditBox 类中都作为公有成员实现。当然,在C# 中我们也可以选择不作为公有成员实现接口。

如果每个成员都明显地指出了被实现的接口,通过这种途径被实现的接口我们称之为显式接口成员(explicit interface member)。 用这种方式我们改写上面的例子:


public class EditBox: IControl, IDataBound {
void IControl.Paint( ) {…}
void IDataBound.Bind(Binder b) {…}
}


显式接口成员只能通过接口调用。例如:


class CTest {
 
  static void Main( ) {
 
   EditBox editbox = new EditBox( ) ;
 
   editbox.Paint( ) ; //错误:不同的方法
 
   IControl control = editbox;
 
   control.Paint( ) ; //调用 EditBox的Paint方法
 
  }
 
 }


上述代码中对editbox.Paint( )的调用是错误的,因为editbox 本身并没有提供这一方法。control.Paint( )是正确的调用方式。

注释:接口本身不提供所定义的成员的实现,它仅仅说明这些成员,这些成员必须依靠实现接口的类或其它接口的支持。

知道了怎样访问接口,我们还要知道怎样实现接口,要实现C#的接口,请看下一节-实现接口

第五节、实现接口

1、显式实现接口成员

为了实现接口,类可以定义显式接口成员执行体(Explicit interface member implementations)。显式接口成员执行体可以是一个方法、一个属性、一个事件或者是一个索引指示器的定义,定义与该成员对应的全权名应保持一致。


using System ;
 
 interface ICloneable {
 
  object Clone( ) ;
 
 }
 
 interface IComparable {
 
  int CompareTo(object other) ;
 
 }
 
 class ListEntry: ICloneable, IComparable {
 
  object ICloneable.Clone( ) {…}
 
  int IComparable.CompareTo(object other) {…}
 
 }


上面的代码中ICloneable.Clone 和IComparable.CompareTo 就是显式接口成员执行体。

说明:

1、不能在方法调用、属性访问以及索引指示器访问中通过全权名访问显式接口成员执行体。事实上,显式接口成员执行体只能通过接口的实例,仅仅引用接口的成员名称来访问。

2、显式接口成员执行体不能使用任何访问限制符,也不能加上abstract, virtual, override或static 修饰符。

3、显式接口成员执行体和其他成员有着不同的访问方式。因为不能在方法调用、属性访问以及索引指示器访问中通过全权名访问,显式接口成员执行体在某种意义上是私有的。但它们又可以通过接口的实例访问,也具有一定的公有性质。

4、只有类在定义时,把接口名写在了基类列表中,而且类中定义的全权名、类型和返回类型都与显式接口成员执行体完全一致时,显式接口成员执行体才是有效的,例如:


class Shape: ICloneable {
object ICloneable.Clone( ) {…}
int IComparable.CompareTo(object other) {…}
}


使用显式接口成员执行体通常有两个目的:

1、因为显式接口成员执行体不能通过类的实例进行访问,这就可以从公有接口中把接口的实现部分单独分离开。如果一个类只在内部使用该接口,而类的使用者不会直接使用到该接口,这种显式接口成员执行体就可以起到作用。

2、显式接口成员执行体避免了接口成员之间因为同名而发生混淆。如果一个类希望对名称和返回类型相同的接口成员采用不同的实现方式,这就必须要使用到显式接口成员执行体。如果没有显式接口成员执行体,那么对于名称和返回类型不同的接口成员,类也无法进行实现。

下面的定义是无效的,因为Shape 定义时基类列表中没有出现接口IComparable。


class Shape: ICloneable
 
 {
 
 object ICloneable.Clone( ) {…}
 
 }
 
 class Ellipse: Shape
 
 {
 
 object ICloneable.Clone( ) {…}
 
 }


在Ellipse 中定义ICloneable.Clone是错误的,因为Ellipse即使隐式地实现了接口ICloneable,ICloneable仍然没有显式地出现在Ellipse定义的基类列表中。

接口成员的全权名必须对应在接口中定义的成员。如下面的例子中,Paint的显式接口成员执行体必须写成IControl.Paint。


using System ;
 
 interface IControl
 
 {
 
  void Paint( ) ;
 
 }
 
 interface ITextBox: IControl
 
 {
 
  void SetText(string text) ;
 
 }
 
 class TextBox: ITextBox
 
 {
 
  void IControl.Paint( ) {…}
 
  void ITextBox.SetText(string text) {…}
 
 }


实现接口的类可以显式实现该接口的成员。当显式实现某成员时,不能通过类实例访问该成员,而只能通过该接口的实例访问该成员。显式接口实现还允许程序员继承共享相同成员名的两个接口,并为每个接口成员提供一个单独的实现。

下面例子中同时以公制单位和英制单位显示框的尺寸。Box类继承 IEnglishDimensions和 IMetricDimensions两个接口,它们表示不同的度量衡系统。两个接口有相同的成员名 Length 和 Width。

程序清单1 DemonInterface.cs


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 IEnglishDimensions.Length( ) {
 
 return lengthInches ;
 
 }
 
 float IEnglishDimensions.Width( ) {
 
 return widthInches ;
 
 }
 
 float IMetricDimensions.Length( ) {
 
 return lengthInches * 2.54f ;
 
 }
 
 float IMetricDimensions.Width( ) {
 
 return widthInches * 2.54f ;
 
 }
 
 public static void Main( ) {
 
 //定义一个实类对象 "myBox"::
 
 Box myBox = new Box(30.0f, 20.0f);
 
 // 定义一个接口" eDimensions"::
 
 IEnglishDimensions eDimensions = (IEnglishDimensions) myBox;
 
 IMetricDimensions mDimensions = (IMetricDimensions) myBox;
 
 // 输出:
 
 System.Console.WriteLine(" Length(in): {0}", eDimensions.Length( ));
 
 System.Console.WriteLine(" Width (in): {0}", eDimensions.Width( ));
 
 System.Console.WriteLine(" Length(cm): {0}", mDimensions.Length( ));
 
 System.Console.WriteLine(" Width (cm): {0}", mDimensions.Width( ));
 
 }
 
 }


输出:Length(in): 30,Width (in): 20,Length(cm): 76.2,Width (cm): 50.8

代码讨论:如果希望默认度量采用英制单位,请正常实现 Length 和 Width 这两个方法,并从 IMetricDimensions 接口显式实现 Length 和 Width 方法:


public float Length( ) {
 
 return lengthInches ;
 
 }
 
 public float Width( ){
 
 return widthInches;
 
 }
 
 float IMetricDimensions.Length( ) {
 
 return lengthInches * 2.54f ;
 
 }
 
 float IMetricDimensions.Width( ) {
 
 return widthInches * 2.54f ;
 
 }


这种情况下,可以从类实例访问英制单位,而从接口实例访问公制单位:


System.Console.WriteLine("Length(in): {0}", myBox.Length( )) ;

System.Console.WriteLine("Width (in): {0}", myBox.Width( )) ;

System.Console.WriteLine("Length(cm): {0}", mDimensions.Length( )) ;

System.Console.WriteLine("Width (cm): {0}", mDimensions.Width( )) ;


2、继承接口实现

接口具有不变性,但这并不意味着接口不再发展。类似于类的继承性,接口也可以继承和发展。

注意:接口继承和类继承不同,首先,类继承不仅是说明继承,而且也是实现继承;而接口继承只是说明继承。也就是说,派生类可以继承基类的方法实现,而派生的接口只继承了父接口的成员方法说明,而没有继承父接口的实现,其次,C#中类继承只允许单继承,但是接口继承允许多继承,一个子接口可以有多个父接口。

接口可以从零或多个接口中继承。从多个接口中继承时,用":"后跟被继承的接口名字,多个接口名之间用","分割。被继承的接口应该是可以访问得到的,比如从private 类型或internal 类型的接口中继承就是不允许的。接口不允许直接或间接地从自身继承。和类的继承相似,接口的继承也形成接口之间的层次结构。

请看下面的例子:



相关评论