熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

基於C#的接口基礎教程之四

2022-06-13   來源: .NET編程 

  第四節訪問接口

  對接口成員的訪問

  對接口方法的調用和采用索引指示器訪問的規則與類中的情況也是相同的如果底層成員的命名與繼承而來的高層成員一致那麼底層成員將覆蓋同名的高層成員但由於接口支持多繼承在多繼承中如果兩個父接口含有同名的成員這就產生了二義性(這也正是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)
   {
    //rsCount() ; 錯誤 Count 有二義性
    //rsCount = ; 錯誤 Count 有二義性
    ((ISequence)rs)Count = ; // 正確
    ((IRing)rs)Count() ; // 正確調用IRingCount
   }
  }

  上面的例子中前兩條語句rs Count()和rs Count = 會產生二義性從而導致編譯時錯誤因此必須顯式地給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)
   {
    // NumAdd() ; 錯誤
    NumAdd() ; // 正確
    ((IInteger)n)Add() ; // 正確
    ((IDouble)n)Add() ; // 正確
   }
  }

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

  接口的多重繼承的問題也會帶來成員訪問上的問題例如

  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 () ; // 調用ILeft FWay
    ((IBase)d) FWay () ; // 調用IBase FWay
    ((ILeft)d) FWay () ; // 調用ILeft FWay
    ((IRight)d) FWay () ; // 調用IBase FWay
   }
  }

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

  類對接口的實現

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

  下面的例子給出了由類來實現接口的例子其中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可以改作方法IcontrolPaint和IdataBoundBind來來實現

  public class EditBox: IControl IDataBound
  {
   void IControlPaint( ) {}
   void IDataBoundBind(Binder b) {}
  }

  因為通過外部指派接口成員實現了每個成員所以用這種方法實現的成員稱為外部接口成員外部接口成員可以只是通過接口來調用例如Paint方法中EditBox的實現可以只是通過創建Icontrol接口來調用

  class Test
  {
   static void Main( )
   {
    EditBox editbox = new EditBox( );
    editboxPaint( ); //錯誤: EditBox 沒有Paint 事件
    IControl control = editbox;
    controlPaint( ); // 調用 EditBox的Paint事件
   }
  }

  上例中類EditBox 從Control 類繼承並同時實現了IControl and IDataBound 接口EditBox 中的Paint 方法來自IControl 接口Bind 方法來自IDataBound 接口二者在EditBox 類中都作為公有成員實現當然在C# 中我們也可以選擇不作為公有成員實現接口

  如果每個成員都明顯地指出了被實現的接口通過這種途徑被實現的接口我們稱之為顯式接口成員(explicit interface member) 用這種方式我們改寫上面的例子

  public class EditBox: IControl IDataBound
  {
   void IControlPaint( ) {…}
   void IDataBoundBind(Binder b) {…}
  }

  顯式接口成員只能通過接口調用例如

  class CTest
  {
   static void Main( )
   {
    EditBox editbox = new EditBox( ) ;
    editboxPaint( ) ; //錯誤:不同的方法
    IControl control = editbox;
    controlPaint( ) ; //調用 EditBox的Paint方法
   }
  }

  上述代碼中對editboxPaint( )的調用是錯誤的因為editbox 本身並沒有提供這一方法controlPaint( )是正確的調用方式

  注釋接口本身不提供所定義的成員的實現它僅僅說明這些成員這些成員必須依靠實現接口的類或其它接口的支持

  知道了怎樣訪問接口我們還要知道怎樣實現接口要實現C#的接口請看下一節實現接口


From:http://tw.wingwit.com/Article/program/net/201311/15729.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.