基於C#的介面基礎教程之四

來源:互聯網
上載者:User
第四節、提供者

   對介面成員的訪問

   對介面方法的調用和採用索引指標訪問的規則與類中的情況也是相同的。如果底層成員的命名與繼承而來的高層成員一致,那麼底層成員將覆蓋同名的高層成員。但由於介面支援多繼承,在多繼承中,如果兩個父介面含有同名的成員,這就產生了二義性(這也正是C#中取消了類的多繼承機制的原因之一),這時需要進行顯式的定義:

using System ;
interface ISequence {
  int Count { get; set; }
}
interface IRing {
  void Count(int i) ;
}
interface IRingSequence: ISequence, IRing { }
  class CTest {
   void Test(IRingSequence rs) {
    //rs.Count(1) ; 錯誤, Count 有二義性
    //rs.Count = 1; 錯誤, Count 有二義性
    ((ISequence)rs).Count = 1; // 正確
    ((IRing)rs).Count(1) ; // 正確調用IRing.Count
   }
}

   上面的例子中,前兩條語句rs .Count(1)和rs .Count = 1會產生二義性,從而導致編譯時間錯誤,因此必須顯式地給rs 指派父介面類型,這種指派在運行時不會帶來額外的開銷。

   再看下面的例子:

using System ;
interface IInteger {
  void Add(int i) ;
}
interface IDouble {
  void Add(double d) ;
}
interface INumber: IInteger, IDouble {}
  class CMyTest {
  void Test(INumber Num) {
   // Num.Add(1) ; 錯誤
   Num.Add(1.0) ; // 正確
   ((IInteger)n).Add(1) ; // 正確
   ((IDouble)n).Add(1) ; // 正確
  }
}

   調用Num.Add(1) 會導致二義性,因為候選的重載方法的參數類型均適用。但是,調用Num.Add(1.0) 是允許的,因為1.0 是浮點數參數類型與方法IInteger.Add()的參數類型不一致,這時只有IDouble.Add 才是適用的。不過只要加入了顯式的指派,就決不會產生二義性。

   介面的多重繼承的問題也會帶來成員訪問上的問題。例如:

interface IBase {
  void FWay(int i) ;
}
interface ILeft: IBase {
  new void FWay (int i) ;
}
interface IRight: IBase
{ void G( ) ; }
interface IDerived: ILeft, IRight { }
class CTest {
  void Test(IDerived d) {
   d. FWay (1) ; // 調用ILeft. FWay
   ((IBase)d). FWay (1) ; // 調用IBase. FWay
   ((ILeft)d). FWay (1) ; // 調用ILeft. FWay
   ((IRight)d). FWay (1) ; // 調用IBase. FWay
  }
}

   上例中,方法IBase.FWay在派生的介面ILeft中被Ileft的成員方法FWay覆蓋了。所以對d. FWay (1)的調用實際上調用了。雖然從IBase-> IRight-> IDerived這條繼承路徑上來看,ILeft.FWay方法是沒有被覆蓋的。我們只要記住這一點:一旦成員被覆蓋以後,所有對其的訪問都被覆蓋以後的成員"攔截"了。
類對介面的實現

   前面我們已經說過,介面定義不包括方法的實現部分。介面可以通過類或結構來實現。我們主要講述通過類來實現介面。用類來實現介面時,介面的名稱必須包含在類定義中的基類列表中。

   下面的例子給出了由類來實現介面的例子。其中ISequence 為一個隊列介面,提供了向隊列尾部添加對象的成員方法Add( ),IRing 為一個迴圈表介面,提供了向環中插入對象的方法Insert(object obj),方法返回插入的位置。類RingSquence 實現了介面ISequence 和介面IRing。

using System ;
interface ISequence {
  object Add( ) ;
}
interface ISequence {
  object Add( ) ;
}
interface IRing {
  int Insert(object obj) ;
}
class RingSequence: ISequence, IRing
{
  public object Add( ) {…}
  public int Insert(object obj) {…}
}

   如果類實現了某個介面,類也隱式地繼承了該介面的所有父介面,不管這些父介面有沒有在類定義的基類表中列出。看下面的例子:

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

   這裡, 介面IcomboBox繼承了ItextBox和IlistBox。類TextBox不僅實現了介面ITextBox,還實現了介面ITextBox 的父介面IControl。

   前面我們已經看到,一個類可以實現多個介面。再看下面的例子:

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

   類EditBox從類Control中派生並且實現了Icontrol和IdataBound。在前面的例子中介面Icontrol中的Paint方法和IdataBound介面中的Bind方法都用類EditBox中的公用成員實現。C#提供一種實現這些方法的可選擇的途徑,這樣可以使執行這些的類避免把這些成員設定為公用的。介面成員可以用有效名稱來實現。例如,類EditBox可以改作方法Icontrol.Paint和IdataBound.Bind來來實現。

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

   因為通過外部指派介面成員實現了每個成員,所以用這種方法實現的成員稱為外部介面成員。外部介面成員可以只是通過介面來調用。例如,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( )是正確的調用方式。

   注釋:介面本身不提供所定義的成員的實現,它僅僅說明這些成員,這些成員必須依靠實現介面的類或其它介面的支援。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.