全面剖析C#接口編程之定義接口

從技術上講,接口是一組包含了函數型方法的數據結構。通過這組數據結構,客戶代碼可以調用組件對象的功能。

定義接口的一般形式爲:

[attributes] [modifiers] interface identifier [:base-list] {interface-body}[;]


說明:

· attributes(可選):附加的定義性信息。

· modifiers(可選):允許使用的修飾符有new和四個訪問修飾符。分別是:new、public、protected、internal、private。在一個接口定義中同一修飾符不允許出現多次,new修飾符只能出現在嵌套接口中,表示覆蓋了繼承而來的同名成員。The public, protected, internal, and private修飾符定義了對接口的訪問權限。

· 指示器和事件。

· identifier:接口名稱。

· base-list(可選):包含一個或多個顯式基接口的列表,接口間由逗號分隔。

· interface-body:對接口成員的定義。

· 接口可以是命名空間或類的成員,並且可以包含下列成員的簽名: 方法、屬性、索引器 。

· 一個接口可從一個或多個基接口繼承。

接口這個概念在C#和Java中非常相似。接口的關鍵詞是interface,一個接口可以擴展一個或者多個其他接口。按照慣例,接口的名字以大寫字母"I"開頭。下面的代碼是C#接口的一個例子,它與Java中的接口完全一樣:

interface IShape  { 
    void Draw ( ) ;
}


如果你從兩個或者兩個以上的接口派生,父接口的名字列表用逗號分隔,如下面的代碼所示:

interface INewInterface: IParent1, IParent2 { }


然而,與Java不同,C#中的接口不能包含域(Field)。另外還要注意,在C#中,接口內的所有方法默認都是公用方法。在Java中,方法定義可以帶有public修飾符(即使這並非必要),但在C#中,顯式爲接口的方法指定public修飾符是非法的。例如,下面的C#接口將產生一個編譯錯誤。

interface IShape { public void Draw( ) ; }


下面的例子定義了一個名爲IControl 的接口,接口中包含一個成員方法Paint:

interface IControl {
void Paint( ) ;
}


在下例中,接口 IInterface從兩個基接口 IBase1 和 IBase2 繼承:

interface IInterface: IBase1, IBase2 {
   void Method1( ) ;
   void Method2( ) ;
}


接口可由類實現。實現的接口的標識符出現在類的基列表中。例如:

class Class1: Iface1, Iface2 {
   // class 成員。
}


類的基列表同時包含基類和接口時,列表中首先出現的是基類。例如:

class ClassA: BaseClass, Iface1, Iface2 {
   // class成員。
}


以下的代碼段定義接口IFace,它只有一個方法:

interface IFace {
  void ShowMyFace( ) ;
}


不能從這個定義實例化一個對象,但可以從它派生一個類。因此,該類必須實現ShowMyFace抽象方法:

class CFace:IFace
{
  public void ShowMyFace( )   {
    Console.WriteLine(" implementation " ) ;
   } 
}


基接口


一個接口可以從零或多個接口繼承,那些被稱爲這個接口的顯式基接口。當一個接口有比零多的顯式基接口時,那麼在接口的定義中的形式爲,接口標識符後面跟着由一個冒號":"和一個用逗號","分開的基接口標識符列表。

接口基:

接口類型列表說明:

· 一個接口的顯式基接口必須至少同接口本身一樣可訪問。例如,在一個公共接口的基接口中指定一個私有或內部的接口是錯誤的。

· 一個接口直接或間接地從它自己繼承是錯誤的。

· 接口的基接口都是顯式基接口,並且是它們的基接口。換句話說,基接口的集合完全由顯式基接口和它們的顯式基接口等等組成。在下面的例子中

interface IControl {
	void Paint( ) ;
}
interface ITextBox: IControl {
	void SetText(string text) ;
}
interface IListBox: IControl {
	void SetItems(string[] items) ;
}
interface IComboBox: ITextBox, IListBox { }


IComboBox 的基接口是IControl, ITextBox, 和 IlistBox。

· 一個接口繼承它的基接口的所有成員。換句話說,上面的接口IComboBox就像Paint一樣繼承成員SetText 和 SetItems。

· 一個實現了接口的類或結構也隱含地實現了所有接口的基接口。

接口主體

一個接口的接口主體定義接口的成員。

interface-body:
{   interface-member-declarationsopt   }

定義接口成員



接口可以包含一個和多個成員,這些成員可以是方法、屬性、索引指示器和事件,但不能是常量、域、操作符、構造函數或析構函數,而且不能包含任何靜態成員。接口定義創建新的定義空間,並且接口定義直接包含的接口成員定義將新成員引入該定義空間。

說明:

· 接口的成員是從基接口繼承的成員和由接口本身定義的成員。

· 接口定義可以定義零個或多個成員。接口的成員必須是方法、屬性、事件或索引器。接口不能包含常數、字段、運算符、實例構造函數、析構函數或類型,也不能包含任何種類的靜態成員。

· 定義一個接口,該接口對於每種可能種類的成員都包含一個:方法、屬性、事件和索引器。

· 接口成員默認訪問方式是public。接口成員定義不能包含任何修飾符,比如成員定義前不能加abstract,public,protected,internal,private,virtual,override 或static 修飾符。

· 接口的成員之間不能相互同名。繼承而來的成員不用再定義,但接口可以定義與繼承而來的成員同名的成員,這時我們說接口成員覆蓋了繼承而來的成員,這不會導致錯誤,但編譯器會給出一個警告。關閉警告提示的方式是在成員定義前加上一個new關鍵字。但如果沒有覆蓋父接口中的成員,使用new關鍵字會導致編譯器發出警告。

· 方法的名稱必須與同一接口中定義的所有屬性和事件的名稱不同。此外,方法的簽名必須與同一接口中定義的所有其他方法的簽名不同。

· 屬性或事件的名稱必須與同一接口中定義的所有其他成員的名稱不同。

· 一個索引器的簽名必須區別於在同一接口中定義的其他所有索引器的簽名。

· 接口方法聲明中的屬性(attributes), 返回類型(return-type), 標識符(identifier)和形式參數列表(formal-parameter-lis)與一個類的方法聲明中的那些有相同的意義。一個接口方法聲明不允許指定一個方法主體,而聲明通常用一個分號結束。

· 接口屬性聲明的訪問符與類屬性聲明的訪問符相對應,除了訪問符主體通常必須用分號。因此,無論屬性是讀寫、只讀或只寫,訪問符都完全確定。

· 接口索引聲明中的屬性(attributes),類型(type)和形式參數列表(formal-parameter-list)與類的索引聲明的那些有相同的意義。

下面例子中接口IMyTest包含了索引指示器、事件E、方法F、屬性P這些成員:

interface IMyTest{
    string this[int index] { get; set; }
    event EventHandler E ;
    void F(int value)  ;
    string P { get; set; }
}
public delegate void EventHandler(object sender, EventArgs e) ;


下面例子中接口IStringList包含每個可能類型成員的接口:一個方法,一個屬性,一個事件和一個索引。

public delegate void StringListEvent(IStringList sender);
public interface IStringList
{
	void Add(string s);
	int Count { get; }
	event StringListEvent Changed;
	string this[int index] { get; set; }
}


接口成員的全權名



使用接口成員也可採用全權名(fully qualified name)。接口的全權名稱是這樣構成的。接口名加小圓點"." 再跟成員名比如對於下面兩個接口:

interface IControl {
    void Paint( ) ;
}
interface ITextBox: IControl {
    void GetText(string text) ;
}


其中Paint 的全權名是IControl.Paint,GetText的全權名是ITextBox. GetText。當然,全權名中的成員名稱必須是在接口中已經定義過的,比如使用ITextBox.Paint.就是不合理的。

如果接口是名字空間的成員,全權名還必須包含名字空間的名稱。

namespace System
{
    public interface IDataTable {
        object Clone( ) ;
    }
}


那麼Clone方法的全權名是System. IDataTable.Clone。

定義好了接口,接下來我們關心的就是怎樣實現對接口的訪問。這部分內容,我將在下一篇文章中和您進一步探討。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章