久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

什么事接口

發布時間:2023/12/10 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 什么事接口 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

假設你設計一個和人交流的程序。
先建立一個接口
interface 人 //定義接口,它代表一個人,
{void Hello(); }//接口虛函數,用來跟這個人說話

但不同的人有不用的交流方式,具體方式用類來實現,比如。
class 美國人:人 //繼承接口“人”
然后,類里實例化接口函數
void Hello(){說hi;}

class 中國人:人 //繼承接口“人”
然后,類里實例化接口函數
void Hello(){說你好;}

class SB:人 //sb也是人
實現 Hello{說xxxxx;}

最后你的程序運行時,就用接口“人”就可以了,
因為不管遇到什么人(美國人,中國人,還是sb),都可以和他們交流了,這就是接口的意義!!!?
??
基于Visual C#的接口基礎教程

???? 組件化程序設計方法繼承并發展了面向對象的程序設計方法。它把對象技術應用于系統設計,對面向對象的程序設計的實現過程作了進一步的抽象。
  接口是是組件化編程的一個重要內容,熟練掌握和使用接口將大大減輕編程的工作量,提高代碼的可重用性,同時也能使你更深入的理解面向對象的思想。

第一節 接口慨述

  接口(interface)用來定義一種程序的協定。實現接口的類或者結構要與接口的定義嚴格一致。有了這個協定,就可以拋開編程語言的限制(理論上)。接口可以從多個基接口繼承,而類或結構可以實現多個接口。接口可以包含方法、屬性、事件和索引器。接口本身不提供它所定義的成員的實現。接口只指定實現該接口的類或接口必須提供的成員。
????? 接口好比一種模版,這種模版定義了對象必須實現的方法,其目的就是讓這些方法可以作為接口實例被引用。接口不能被實例化。類可以實現多個接口并且通過這些實現的接口被索引。接口變量只能索引實現該接口的類的實例。例子:

?

interface IMyExample {
 string this[int index] { get ; set ; }
 event EventHandler Even ;
 void Find(int value) ;
 string Point { get ; set ; }
}
public delegate void EventHandler(object sender, Event e) ;?

?

  上面例子中的接口包含一個索引this、一個事件Even、一個方法Find和一個屬性Point。

  接口可以支持多重繼承。就像在下例中,接口"IComboBox"同時從"ITextBox"和"IListBox"繼承。

?

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

?

  類和結構可以多重實例化接口。就像在下例中,類"EditBox"繼承了類"Control",同時從"IDataBound"和"IControl"繼承。

?

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

?

  在上面的代碼中,"Paint"方法從"IControl"接口而來;"Bind"方法從"IDataBound"接口而來,都以"public"的身份在"EditBox"類中實現。

  說明:

  1、C#中的接口是獨立于類來定義的。這與 C++模型是對立的,在 C++中接口實際上就是抽象基類。

  2、接口和類都可以繼承多個接口。

  3、而類可以繼承一個基類,接口根本不能繼承類。這種模型避免了 C++的多繼承問題,C++中不同基類中的實現可能出現沖突。因此也不再需要諸如虛擬繼承和顯式作用域這類復雜機制。C#的簡化接口模型有助于加快應用程序的開發。

  4、一個接口定義一個只有抽象成員的引用類型。C#中一個接口實際所做的,僅僅只存在著方法標志,但根本就沒有執行代碼。這就暗示了不能實例化一個接口,只能實例化一個派生自該接口的對象。

  5、接口可以定義方法、屬性和索引。所以,對比一個類,接口的特殊性是:當定義一個類時,可以派生自多重接口,而你只能可以從僅有的一個類派生。

?????? 接口與組件

  接口描述了組件對外提供的服務。在組件和組件之間、組件和客戶之間都通過接口進行交互。因此組件一旦發布,它只能通過預先定義的接口來提供合理的、一致的服務。這種接口定義之間的穩定性使客戶應用開發者能夠構造出堅固的應用。一個組件可以實現多個組件接口,而一個特定的組件接口也可以被多個組件來實現。

  組件接口必須是能夠自我描述的。這意味著組件接口應該不依賴于具體的實現,將實現和接口分離徹底消除了接口的使用者和接口的實現者之間的耦合關系,增強了信息的封裝程度。同時這也要求組件接口必須使用一種與組件實現無關的語言。目前組件接口的描述標準是IDL語言。

  由于接口是組件之間的協議,因此組件的接口一旦被發布,組件生產者就應該盡可能地保持接口不變,任何對接口語法或語義上的改變,都有可能造成現有組件與客戶之間的聯系遭到破壞。

  每個組件都是自主的,有其獨特的功能,只能通過接口與外界通信。當一個組件需要提供新的服務時,可以通過增加新的接口來實現。不會影響原接口已存在的客戶。而新的客戶可以重新選擇新的接口來獲得服務。

  組件化程序設計

  組件化程序設計方法繼承并發展了面向對象的程序設計方法。它把對象技術應用于系統設計,對面向對象的程序設計的實現過程作了進一步的抽象。我們可以把組件化程序設計方法用作構造系統的體系結構層次的方法,并且可以使用面向對象的方法很方便地實現組件。

  組件化程序設計強調真正的軟件可重用性和高度的互操作性。它側重于組件的產生和裝配,這兩方面一起構成了組件化程序設計的核心。組件的產生過程不僅僅是應用系統的需求,組件市場本身也推動了組件的發展,促進了軟件廠商的交流與合作。組件的裝配使得軟件產品可以采用類似于搭積木的方法快速地建立起來,不僅可以縮短軟件產品的開發周期,同時也提高了系統的穩定性和可靠性。

  組件程序設計的方法有以下幾個方面的特點:

  1、編程語言和開發環境的獨立性;

  2、組件位置的透明性;

  3、組件的進程透明性;

  4、可擴充性;

  5、可重用性;

  6、具有強有力的基礎設施;

  7、系統一級的公共服務;

  C#語言由于其許多優點,十分適用于組件編程。但這并不是說C#是一門組件編程語言,也不是說C#提供了組件編程的工具。我們已經多次指出,組件應該具有與編程語言無關的特性。請讀者記住這一點:組件模型是一種規范,不管采用何種程序語言設計組件,都必須遵守這一規范。比如組裝計算機的例子,只要各個廠商為我們提供的配件規格、接口符合統一的標準,這些配件組合起來就能協同工作,組件編程也是一樣。我們只是說,利用C#語言進行組件編程將會給我們帶來更大的方便。

  知道了什么是接口,接下來就是怎樣定義接口,請看下一節--定義接口。

  第二節 定義接口

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

  定義接口的一般形式為:


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


  說明:
?????? 1、attributes(可選):附加的定義性信息。

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

  3、指示器和事件。

  4、identifier:接口名稱。

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

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

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

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

??????? 接口這個概念在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 " ) ;
 }
}?

基接口

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

  接口基:

  :接口類型列表說明:

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

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

  3、接口的基接口都是顯式基接口,并且是它們的基接口。換句話說,基接口的集合完全由顯式基接口和它們的顯式基接口等等組成。在下面的例子中
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。

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

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

  接口主體

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


interface-body:
{ interface-member-declarationsopt }


  定義接口主要是定義接口成員,請看下一節--定義接口成員。


第三節 定義接口成員

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

  說明:
?????? 1、接口的成員是從基接口繼承的成員和由接口本身定義的成員。

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

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

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

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

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

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

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

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

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

  11、接口索引聲明中的屬性(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。

  定義好了接口,接下來就是怎樣訪問接口,請看下一節--訪問接口

第四節、訪問接口

  對接口成員的訪問

  對接口方法的調用和采用索引指示器訪問的規則與類中的情況也是相同的。如果底層成員的命名與繼承而來的高層成員一致,那么底層成員將覆蓋同名的高層成員。但由于接口支持多繼承,在多繼承中,如果兩個父接口含有同名的成員,這就產生了二義性(這也正是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( )是正確的調用方式。

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

  知道了怎樣訪問接口,我們還要知道怎樣實現接口,要實現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( )) ;

?

  4、映射接口

  類必須為在基類表中列出的所有接口的成員提供具體的實現。
在類中定位接口成員的實現稱之為接口映射(interface mapping )。

  映射,數學上表示一一對應的函數關系。接口映射的含義也是一樣,接口通過類來實現,
那么對于在接口中定義的每一個成員,都應該對應著類的一個成員來為它提供具體的實現。

  類的成員及其所映射的接口成員之間必須滿足下列條件:

  1、如果A和B都是成員方法,那么A和B的名稱、類型、形參表(包括參數個數和每一個參數的類型)都應該是一致的。

  2、如果A和B都是屬性,那么A和B的名稱、類型應當一致,而且A和B的訪問器也是類似的。但如果A不是顯式接口成員執行體,A允許增加自己的訪問器。

  3、如果A和B都是時間那么A和B的名稱、類型應當一致。

  4、如果A和B都是索引指示器,那么A和B的類型、形參表(包括參數個數和每一個參數的類型)應當一致。而且A和B的訪問器也是類似的。但如果A不是顯式接口成員執行體,A允許增加自己的訪問器。

  那么,對于一個接口成員,怎樣確定由哪一個類的成員來實現呢?即一個接口成員映射的是哪一個類的成員?在這里,我們敘述一下接口映射的過程。假設類C實現了一個接口IInterface,Member是接口IInterface中的一個成員,在定位由誰來實現接口成員Member,即Member的映射過程是這樣的:

  1、如果C中存在著一個顯式接口成員執行體,該執行體與接口IInterface 及其成員Member相對應,則由它來實現Member 成員。

  2、如果條件(1)不滿足,且C中存在著一個非靜態的公有成員,該成員與接口成員Member相對應,則由它來實現Member 成員。

  3、如果上述條件仍不滿足,則在類C定義的基類列表中尋找一個C 的基類D,用D來代替C。

  4、重復步驟1-- 3 ,遍歷C的所有直接基類和非直接基類,直到找到一個滿足條件的類的成員。

  5、如果仍然沒有找到,則報告錯誤。

  下面是一個調用基類方法來實現接口成員的例子。類Class2 實現了接口Interface1,類Class2 的基類Class1 的成員也參與了接口的映射,也就是說類Class2 在對接口Interface1進行實現時,使用了類Class1提供的成員方法F來實現接口Interface1的成員方法F:

?


?

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 類型的接口中繼承就是不允許的。接口不允許直接或間接地從自身繼承。和類的繼承相似,接口的繼承也形成接口之間的層次結構。


請看下面的例子:


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


對一個接口的繼承也就繼承了接口的所有成員,上面的例子中接口ITextBox和IListBox都從接口IControl中繼承,也就繼承了接口 IControl的Paint方法。接口IComboBox從接口ITextBox和IListBox中繼承,因此它應該繼承了接口ITextBox的 SetText方法和IListBox的SetItems方法,還有IControl的Paint方法。
一個類繼承了所有被它的基本類提供的接口實現程序。


不通過顯式的實現一個接口,一個派生類不能用任何方法改變它從它的基本類繼承的接口映射。例如,在聲明中


interface IControl {
void Paint( );
}
class Control: IControl {
public void Paint( ) {...}
}
class TextBox: Control {
new public void Paint( ) {...}
}


TextBox 中的方法Paint 隱藏了Control中的方法Paint ,但是沒有改變從Control.Paint 到IControl.Paint 的映射,而通過類實例和接口實例調用Paint將會有下面的影響


Control c = new Control( ) ;
TextBox t = new TextBox( ) ;
IControl ic = c ;
IControl it = t ;
c.Paint( ) ; // 影響Control.Paint( ) ;
t.Paint( ) ; // 影響TextBox.Paint( ) ;
ic.Paint( ) ; // 影響Control.Paint( ) ;
it.Paint( ) ; // 影響Control.Paint( ) ;


但是,當一個接口方法被映射到一個類中的虛擬方法,派生類就不可能覆蓋這個虛擬方法并且改變接口的實現函數。例如,把上面的聲明重新寫為


interface IControl {
void Paint( ) ;
}
class Control: IControl {
public virtual void Paint( ) {...}
}
class TextBox: Control {
public override void Paint( ) {...}
}


就會看到下面的結果:


Control c = new Control( ) ;
TextBox t = new TextBox( ) ;
IControl ic = c ;
IControl it = t ;
c.Paint( ) ; // 影響Control.Paint( );
t.Paint( ) ; // 影響TextBox.Paint( );
ic.Paint( ) ; // 影響Control.Paint( );
it.Paint( ) ; // 影響TextBox.Paint( );


由于顯式接口成員實現程序不能被聲明為虛擬的,就不可能覆蓋一個顯式接口成員實現程序。一個顯式接口成員實現程序調用另外一個方法是有效的,而另外的那個方法可以被聲明為虛擬的以便讓派生類可以覆蓋它。例如:


interface IControl {
void Paint( ) ;
}
class Control: IControl {
void IControl.Paint( ) { PaintControl( ); }
protected virtual void PaintControl( ) {...}
}
class TextBox: Control {
protected override void PaintControl( ) {...}
}


這里,從Control 繼承的類可以通過覆蓋方法PaintControl 來對IControl.Paint 的實現程序進行特殊化。


3、重新實現接口


我們已經介紹過,派生類可以對基類中已經定義的成員方法進行重載。類似的概念引入到類對接口的實現中來,叫做接口的重實現(re- implementation)。繼承了接口實現的類可以對接口進行重實現。這個接口要求是在類定義的基類列表中出現過的。對接口的重實現也必須嚴格地遵 守首次實現接口的規則,派生的接口映射不會對為接口的重實現所建立的接口映射產生任何影響。


下面的代碼給出了接口重實現的例子:


interface IControl {
void Paint( ) ;
class Control: IControl
void IControl.Paint( ) {…}
class MyControl: Control, IControl
public void Paint( ) {}
}


實際上就是:Control把IControl.Paint映射到了Control.IControl.Paint上,但這并不影響在 MyControl中的重實現。在MyControl中的重實現中,IControl.Paint被映射到MyControl.Paint 之上。


在接口的重實現時,繼承而來的公有成員定義和繼承而來的顯式接口成員的定義參與到接口映射的過程。


using System ;
interface IMethods {
void F( ) ;
void G( ) ;
void H( ) ;
void I( ) ;
}
class Base: IMethods {
void IMethods.F( ) { }
void IMethods.G( ) { }
public void H( ) { }
public void I( ) { }
}
class Derived: Base, IMethods {
public void F( ) { }
void IMethods.H( ) { }
}


這里,接口IMethods在Derived中的實現把接口方法映射到了Derived.F,Base.IMethods.G, Derived.IMethods.H, 還有Base.I。前面我們說過,類在實現一個接口時,同時隱式地實現了該接口的所有父接口。同樣,類在重實現一個接口時同時,隱式地重實現了該接口的所 有父接口。


using System ;
interface IBase {
void F( ) ;
}
interface IDerived: IBase {
void G( ) ;
}
class C: IDerived {
void IBase.F( ) {
//對F 進行實現的代碼…
}
void IDerived.G( ) {
//對G 進行實現的代碼…
}
}
class D: C, IDerived {
public void F( ) {
//對F 進行實現的代碼…
}
public void G( ) {
//對G 進行實現的代碼…
}
}


這里,對IDerived的重實現也同樣實現了對IBase的重實現,把IBase.F 映射到了D.F。


4、映射接口


類必須為在基類表中列出的所有接口的成員提供具體的實現。在類中定位接口成員的實現稱之為接口映射(interface mapping )。


映射,數學上表示一一對應的函數關系。接口映射的含義也是一樣,接口通過類來實現,那么對于在接口中定義的每一個成員,都應該對應著類的一個成員來為它提供具體的實現。


類的成員及其所映射的接口成員之間必須滿足下列條件:


1、如果A和B都是成員方法,那么A和B的名稱、類型、形參表(包括參數個數和每一個參數的類型)都應該是一致的。


2、如果A和B都是屬性,那么A和B的名稱、類型應當一致,而且A和B的訪問器也是類似的。但如果A不是顯式接口成員執行體,A允許增加自己的訪問器。


3、如果A和B都是時間那么A和B的名稱、類型應當一致。


4、如果A和B都是索引指示器,那么A和B的類型、形參表(包括參數個數和每一個參數的類型)應當一致。而且A和B的訪問器也是類似的。但如果A不是顯式接口成員執行體,A允許增加自己的訪問器。


那么,對于一個接口成員,怎樣確定由哪一個類的成員來實現呢?即一個接口成員映射的是哪一個類的成員?在這里,我們敘述一下接口映射的過程。假設類C 實現了一個接口IInterface,Member是接口IInterface中的一個成員,在定位由誰來實現接口成員Member,即Member的映 射過程是這樣的:


1、如果C中存在著一個顯式接口成員執行體,該執行體與接口IInterface 及其成員Member相對應,則由它來實現Member 成員。


2、如果條件(1)不滿足,且C中存在著一個非靜態的公有成員,該成員與接口成員Member相對應,則由它來實現Member 成員。


3、如果上述條件仍不滿足,則在類C定義的基類列表中尋找一個C 的基類D,用D來代替C。


4、重復步驟1-- 3 ,遍歷C的所有直接基類和非直接基類,直到找到一個滿足條件的類的成員。


5、如果仍然沒有找到,則報告錯誤。


下面是一個調用基類方法來實現接口成員的例子。類Class2 實現了接口Interface1,類Class2 的基類Class1 的成員也參與了接口的映射,也就是說類Class2 在對接口Interface1進行實現時,使用了類Class1提供的成員方法F來實現接口Interface1的成員方法F:


interface Interface1 {
void F( ) ;
}
class Class1 {
public void F( ) { }
public void G( ) { }
}
class Class2: Class1, Interface1 {
new public void G( ) {}
}


注意:接口的成員包括它自己定義的成員,而且包括該接口所有父接口定義的成員。在接口映射時,不僅要對接口定義體中顯式定義的所有成員進行映射,而且要對隱式地從父接口那里繼承來的所有接口成員進行映射。


在進行接口映射時,還要注意下面兩點:


1、在決定由類中的哪個成員來實現接口成員時,類中顯式說明的接口成員比其它成員優先實現。


2、使用Private、protected和static修飾符的成員不能參與實現接口映射。例如:


interface ICloneable {
object Clone( ) ;
}
class C: ICloneable {
object ICloneable.Clone( ) {…}
public object Clone( ) {…}
}


例子中成員ICloneable.Clone 稱為接口ICloneable 的成員Clone 的實現者,因為它是顯式說明的接口成員,比其它成員有著更高的優先權。


如果一個類實現了兩個或兩個以上名字、類型和參數類型都相同的接口,那么類中的一個成員就可能實現所有這些接口成員:


interface IControl {
void Paint( ) ;
}
interface IForm {
void Paint( ) ;
}
class Page: IControl, IForm {
public void Paint( ) {…}
}


這里,接口IControl和IForm的方法Paint都映射到了類Page中的Paint方法。當然也可以分別用顯式的接口成員分別實現這兩個方法:


interface IControl {
void Paint( ) ;
}
interface IForm {
void Paint( ) ;
}
class Page: IControl, IForm {
public void IControl.Paint( ) {
//具體的接口實現代碼
}
public void IForm.Paint( ) {
//具體的接口實現代碼
}
}


上面的兩種寫法都是正確的。但是如果接口成員在繼承中覆蓋了父接口的成員,那么對該接口成員的實現就可能必須映射到顯式接口成員執行體。看下面的例子:


interface IBase {
int P { get; }
}
interface IDerived: IBase {
new int P( ) ;
}


接口IDerived從接口IBase中繼承,這時接口IDerived 的成員方法覆蓋了父接口的成員方法。因為這時存在著同名的兩個接口成員,那么對這兩個接口成員的實現如果不采用顯式接口成員執行體,編譯器將無法分辨接口 映射。所以,如果某個類要實現接口IDerived,在類中必須至少定義一個顯式接口成員執行體。采用下面這些寫法都是合理的:


//一:對兩個接口成員都采用顯式接口成員執行體來實現
lass C: IDerived {
int IBase.P
get
{ //具體的接口實現代碼 }
int IDerived.P( ){
//具體的接口實現代碼 }
}
//二:對Ibase 的接口成員采用顯式接口成員執行體來實現
class C: IDerived {
int IBase.P
get {//具體的接口實現代碼}
public int P( ){
//具體的接口實現代碼 }
}
//三:對IDerived 的接口成員采用顯式接口成員執行體來實現
class C: IDerived{
public int P
get {//具體的接口實現代碼}
int IDerived.P( ){
//具體的接口實現代碼}
}


另一種情況是,如果一個類實現了多個接口,這些接口又擁有同一個父接口,這個父接口只允許被實現一次。


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


上面的例子中,類ComboBox實現了三個接口:IControl,ITextBox和IListBox。如果認為ComboBox不僅實現了 IControl接口,而且在實現ITextBox和IListBox的同時,又分別實現了它們的父接口IControl。實際上,對接口 ITextBox 和IListBox 的實現,分享了對接口IControl 的實現。


我們對C#的接口有了較全面的認識,基本掌握了怎樣應用C#的接口編程,但事實上,C#的不僅僅應用于.net平臺,它同樣支持以前的COM,可以實現COM類到.NET類的轉換,如C#調用API。欲了解這方面的知識,請看下一節-接口轉換。
?
百度空間 | 百度首頁 | 登錄 想想再定 主頁博客相冊|個人檔案 |好友??? 查看文章?????
C#接口基礎(6) 2009-07-30 16:44 第四節、訪問接口

對接口成員的訪問


對接口方法的調用和采用索引指示器訪問的規則與類中的情況也是相同的。如果底層成員的命名與繼承而來的高層成員一致,那么底層成員將覆蓋同名的高層成 員。但由于接口支持多繼承,在多繼承中,如果兩個父接口含有同名的成員,這就產生了二義性(這也正是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( )是正確的調用方式。


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


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


類對接口的實現


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


下面的例子給出了由類來實現接口的例子。其中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( )是正確的調用方式。


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

?第一節 接口慨述

接口(interface)用來定義一種程序的協定。實現接口的類或者結構要與接口的定義嚴格一致。
有了這個協定,就可以拋開編程語言的限制(理論 上)。接口可以從多個基接口繼承,
而類或結構可以實現多個接口。接口可以包含方法、屬性、事件和索引器。
接口本身不提供它所定義的成員的實現。接口只指定 實現該接口的類或接口必須提供的成員。


接口好比一種模版,這種模版定義了對象必須實現的方法,其目的就是讓這些方法可以作為接口實例被引用。
接口不能被實例化。類可以實現多個接口并且通過這些實現的接口被索引。
接口變量只能索引實現該接口的類的實例。例子:


interface IMyExample {
string this[int index] { get ; set ; }
event EventHandler Even ;
void Find(int value) ;
string Point { get ; set ; }
}
public delegate void EventHandler(object sender, Event e) ;


上面例子中的接口包含一個索引this、一個事件Even、一個方法Find和一個屬性Point。


接口可以支持多重繼承。就像在下例中,接口"IComboBox"同時從"ITextBox"和"IListBox"繼承。


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


類和結構可以多重實例化接口。就像在下例中,類"EditBox"繼承了類"Control",
同時從"IDataBound"和"IControl"繼承。


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


在上面的代碼中,"Paint"方法從"IControl"接口而來;"Bind"方法從"IDataBound"接口而來,
都以"public"的身份在"EditBox"類中實現。


說明:


1、C#中的接口是獨立于類來定義的。這與 C++模型是對立的,在 C++中接口實際上就是抽象基類。


2、接口和類都可以繼承多個接口。


3、而類可以繼承一個基類,接口根本不能繼承類。這種模型避免了 C++的多繼承問題,
C++中不同基類中的實現可能出現沖突。因此也不再需要諸如虛擬繼承和顯式作用域這類復雜機制。
C#的簡化接口模型有助于加快應用程序的開發。


4、一個接口定義一個只有抽象成員的引用類型。C#中一個接口實際所做的,僅僅只存在著方法標志,
但根本就沒有執行代碼。這就暗示了不能實例化一個接口,只能實例化一個派生自該接口的對象。


5、接口可以定義方法、屬性和索引。所以,對比一個類,接口的特殊性是:當定義一個類時,可以派生自多重接口,
而你只能可以從僅有的一個類派生。

接口與組件


接口描述了組件對外提供的服務。在組件和組件之間、組件和客戶之間都通過接口進行交互。
因此組件一旦發布,它只能通過預先定義的接口來提供合理的、一 致的服務。
這種接口定義之間的穩定性使客戶應用開發者能夠構造出堅固的應用。
一個組件可以實現多個組件接口,而一個特定的組件接口也可以被多個組件來實 現。


組件接口必須是能夠自我描述的。這意味著組件接口應該不依賴于具體的實現,
將實現和接口分離徹底消除了接口的使用者和接口的實現者之間的耦合關系,增強了信息的封裝程度。
同時這也要求組件接口必須使用一種與組件實現無關的語言。目前組件接口的描述標準是IDL語言。


由于接口是組件之間的協議,因此組件的接口一旦被發布,組件生產者就應該盡可能地保持接口不變,
任何對接口語法或語義上的改變,都有可能造成現有組件與客戶之間的聯系遭到破壞。


每個組件都是自主的,有其獨特的功能,只能通過接口與外界通信。當一個組件需要提供新的服務時,
可以通過增加新的接口來實現。不會影響原接口已存在的客戶。而新的客戶可以重新選擇新的接口來獲得服務。


組件化程序設計


組件化程序設計方法繼承并發展了面向對象的程序設計方法。它把對象技術應用于系統設計,
對面向對象的程序設計的實現過程作了進一步的抽象。我們可以把組件化程序設計方法用作構造系統的體系結構層次的方法,
并且可以使用面向對象的方法很方便地實現組件。


組件化程序設計強調真正的軟件可重用性和高度的互操作性。它側重于組件的產生和裝配,這兩方面一起構成了組件化程序設計的核心。
組件的產生過程不僅僅 是應用系統的需求,組件市場本身也推動了組件的發展,促進了軟件廠商的交流與合作。
組件的裝配使得軟件產品可以采用類似于搭積木的方法快速地建立起來,不 僅可以縮短軟件產品的開發周期,
同時也提高了系統的穩定性和可靠性。


組件程序設計的方法有以下幾個方面的特點:


1、編程語言和開發環境的獨立性;


2、組件位置的透明性;


3、組件的進程透明性;


4、可擴充性;


5、可重用性;


6、具有強有力的基礎設施;


7、系統一級的公共服務;


C#語言由于其許多優點,十分適用于組件編程。但這并不是說C#是一門組件編程語言,

也不是說C#提供了組件編程的工具。我們已經多次指出,組件應該 具有與編程語言無關的特性。

請讀者記住這一點:組件模型是一種規范,不管采用何種程序語言設計組件,都必須遵守這一規范。

比如組裝計算機的例子,只要各個 廠商為我們提供的配件規格、接口符合統一的標準,這些配件組合起來就能協同工作,

組件編程也是一樣。我們只是說,利用C#語言進行組件編程將會給我們帶來 更大的方便。


知道了什么是接口,接下來就是怎樣定義接口,請看下一節--定義接口。


第二節 定義接口


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


定義接口的一般形式為:
[attributes] [modifiers] interface identifier [:base-list] {interface-body}[;]


說明:


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


2、modifiers(可選): 允許使用的修飾符有 new 和四個訪問修飾符。分別是:new、public、protected、internal、 private。

在一個接口定義中同一修飾符不允許出現多次,new 修飾符只能出現在嵌套接口中,表示覆蓋了繼承而來的同名成員。

The public, protected, internal, and private 修飾符定義了對接口的訪問權限。


3、指示器和事件。


4、identifier:接口名稱。


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


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


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


8、一個接口可從一個或多個基接口繼承。?


接口這個概念在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 " ) ;
}
}


基接口


一個接口可以從零或多個接口繼承,那些被稱為這個接口的顯式基接口。

當一個接口有比零多的顯式基接口時,那么在接口的定義中的形式為,

接口標識符后面跟著由一個冒號":"和一個用逗號","分開的基接口標識符列表。


接口基:


:接口類型列表說明:


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


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


3、接口的基接口都是顯式基接口,并且是它們的基接口。

換句話說,基接口的集合完全由顯式基接口和它們的顯式基接口等等組成。在下面的例子中
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。


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


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


接口主體


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

?

interface-body:
{ interface-member-declarationsopt }


定義接口主要是定義接口成員,請看下一節--定義接口成員。


第三節 定義接口成員


接口可以包含一個和多個成員,這些成員可以是方法、屬性、索引指示器和事件,但不能是常量、域、操作符、

構造函數或析構函數,而且不能包含任何靜態成員。接口定義創建新的定義空間,并且接口定義直

?接包含的接口成員定義將新成員引入該定義空間。


說明:


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


2、接口定義可以定義零個或多個成員。接口的成員必須是方法、屬性、事件或索引器。

接口不能包含常數、字段、運算符、實例構造函數、析構函數或類型,也不能包含任何種類的靜態成員。


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


4、接口成員默認訪問方式是public。接口成員定義不能包含任何修飾符,

比如成員定義前不能加abstract,public,protected,internal,private,virtual,override 或static 修飾符。


5、接口的成員之間不能相互同名。繼承而來的成員不用再定義,

但接口可以定義與繼承而來的成員同名的成員,這時我們說接口成員覆蓋了繼承而來的成員, 這不會導致錯誤,

但編譯器會給出一個警告。關閉警告提示的方式是在成員定義前加上一個new關鍵字。

但如果沒有覆蓋父接口中的成員,使用new 關鍵字會導致編譯器發出警告。


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


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


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


9、接口方法聲明中的屬性(attributes), 返回類型(return-type), 標識符(identifier),

和形式參數列表(formal-parameter-lis)與一個類的方法聲明中的那些有相同的意義。

一個接口方法聲明不允許指定一個方法主體,而聲明 通常用一個分號結束。


10、接口屬性聲明的訪問符與類屬性聲明的訪問符相對應,除了訪問符主體通常必須用分號。

因此,無論屬性是讀寫、只讀或只寫,訪問符都完全確定。


11、接口索引聲明中的屬性(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。


定義好了接口,接下來就是怎樣訪問接口,請看下一節--訪問接口?

?

假設你設計一個和人交流的程序。
先建立一個接口 interface 人 //定義接口,它代表一個人,

{void Hello(); }//接口虛函數,用來跟這個人說話 但不同的人有不用的交流方式,具體方式用類來實現,比如。

?class 美國人:人 //繼承接口“人” 然后,類里實例化接口函數

void Hello(){說hi;}

class 中國人:人 //繼承接口“人” 然后,類里實例化接口函數 void Hello(){說你好;}

?class SB:人 //sb也是人 實現 Hello{說xxxxx;} 最后你的程序運行時,就用接口“人”就可以了,

因為不管遇到什么人(美國人,中國人,還是sb),都可以和他們交流了,這就是接口的意義!!!
?


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 類型的接口中繼承就是不允許的。接口不允許直接或間接地從自身繼承。
和類的繼承相似,接口的繼承也形成接口之間的層次結構。


請看下面的例子:


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


對一個接口的繼承也就繼承了接口的所有成員,上面的例子中接口ITextBox和IListBox都從接口IControl中繼承,

也就繼承了接口 IControl的Paint方法。接口IComboBox從接口ITextBox和IListBox中繼承,因此它應該繼承了接口ITextBox的 SetText方法和IListBox的SetItems方法,還有IControl的Paint方法。
一個類繼承了所有被它的基本類提供的接口實現程序。


不通過顯式的實現一個接口,一個派生類不能用任何方法改變它從它的基本類繼承的接口映射。例如,在聲明中


interface IControl {
void Paint( );
}
class Control: IControl {
public void Paint( ) {...}
}
class TextBox: Control {
new public void Paint( ) {...}
}


TextBox 中的方法Paint 隱藏了Control中的方法Paint ,但是沒有改變從Control.Paint 到IControl.Paint 的映射,
而通過類實例和接口實例調用Paint將會有下面的影響


Control c = new Control( ) ;
TextBox t = new TextBox( ) ;
IControl ic = c ;
IControl it = t ;
c.Paint( ) ; // 影響Control.Paint( ) ;
t.Paint( ) ; // 影響TextBox.Paint( ) ;
ic.Paint( ) ; // 影響Control.Paint( ) ;
it.Paint( ) ; // 影響Control.Paint( ) ;


但是,當一個接口方法被映射到一個類中的虛擬方法,派生類就不可能覆蓋這個虛擬方法并且改變接口的實現函數。

例如,把上面的聲明重新寫為


interface IControl {
void Paint( ) ;
}
class Control: IControl {
public virtual void Paint( ) {...}
}
class TextBox: Control {
public override void Paint( ) {...}
}


就會看到下面的結果:


Control c = new Control( ) ;
TextBox t = new TextBox( ) ;
IControl ic = c ;
IControl it = t ;
c.Paint( ) ; // 影響Control.Paint( );
t.Paint( ) ; // 影響TextBox.Paint( );
ic.Paint( ) ; // 影響Control.Paint( );
it.Paint( ) ; // 影響TextBox.Paint( );


由于顯式接口成員實現程序不能被聲明為虛擬的,就不可能覆蓋一個顯式接口成員實現程序。

一個顯式接口成員實現程序調用另外一個方法是有效的,而另外的那個方法可以被聲明為虛擬的以便讓派生類可以覆蓋它。例如:


interface IControl {
void Paint( ) ;
}
class Control: IControl {
void IControl.Paint( ) { PaintControl( ); }
protected virtual void PaintControl( ) {...}
}
class TextBox: Control {
protected override void PaintControl( ) {...}
}


這里,從Control 繼承的類可以通過覆蓋方法PaintControl 來對IControl.Paint 的實現程序進行特殊化。


3、重新實現接口


我們已經介紹過,派生類可以對基類中已經定義的成員方法進行重載。類似的概念引入到類對接口的實現中來,

叫做接口的重實現(re- implementation)。繼承了接口實現的類可以對接口進行重實現。

這個接口要求是在類定義的基類列表中出現過的。對接口的重實現也必須嚴格地遵 守首次實現接口的規則,

派生的接口映射不會對為接口的重實現所建立的接口映射產生任何影響。


下面的代碼給出了接口重實現的例子:


interface IControl {
void Paint( ) ;
class Control: IControl
void IControl.Paint( ) {…}
class MyControl: Control, IControl
public void Paint( ) {}
}


實際上就是:Control把IControl.Paint映射到了Control.IControl.Paint上,但這并不影響在 MyControl中的重實現。

在MyControl中的重實現中,IControl.Paint被映射到MyControl.Paint 之上。


在接口的重實現時,繼承而來的公有成員定義和繼承而來的顯式接口成員的定義參與到接口映射的過程。


using System ;
interface IMethods {
void F( ) ;
void G( ) ;
void H( ) ;
void I( ) ;
}
class Base: IMethods {
void IMethods.F( ) { }
void IMethods.G( ) { }
public void H( ) { }
public void I( ) { }
}
class Derived: Base, IMethods {
public void F( ) { }
void IMethods.H( ) { }
}


這里,接口IMethods在Derived中的實現把接口方法映射到了Derived.F,Base.IMethods.G, Derived.IMethods.H,
?還有Base.I。前面我們說過,類在實現一個接口時,同時隱式地實現了該接口的所有父接口。
同樣,類在重實現一個接口時同時,隱式地重實現了該接口的所 有父接口。


using System ;
interface IBase {
void F( ) ;
}
interface IDerived: IBase {
void G( ) ;
}
class C: IDerived {
void IBase.F( ) {
//對F 進行實現的代碼…
}
void IDerived.G( ) {
//對G 進行實現的代碼…
}
}
class D: C, IDerived {
public void F( ) {
//對F 進行實現的代碼…
}
public void G( ) {
//對G 進行實現的代碼…
}
}


這里,對IDerived的重實現也同樣實現了對IBase的重實現,把IBase.F 映射到了D.F。


4、映射接口


類必須為在基類表中列出的所有接口的成員提供具體的實現。在類中定位接口成員的實現稱之為接口映射(interface mapping )。


映射,數學上表示一一對應的函數關系。接口映射的含義也是一樣,接口通過類來實現,那么對于在接口中定義的每一個成員,都應該對應著類的一個成員來為它提供具體的實現。


類的成員及其所映射的接口成員之間必須滿足下列條件:


1、如果A和B都是成員方法,那么A和B的名稱、類型、形參表(包括參數個數和每一個參數的類型)都應該是一致的。


2、如果A和B都是屬性,那么A和B的名稱、類型應當一致,而且A和B的訪問器也是類似的。但如果A不是顯式接口成員執行體,

A允許增加自己的訪問器。


3、如果A和B都是時間那么A和B的名稱、類型應當一致。


4、如果A和B都是索引指示器,那么A和B的類型、形參表(包括參數個數和每一個參數的類型)應當一致。而且A和B的訪問器也是類似的。

但如果A不是顯式接口成員執行體,A允許增加自己的訪問器。


那么,對于一個接口成員,怎樣確定由哪一個類的成員來實現呢?即一個接口成員映射的是哪一個類的成員?

在這里,我們敘述一下接口映射的過程。假設類C 實現了一個接口IInterface,Member是接口IInterface中的一個成員,在定位由誰來實現接口成員Member,即Member的映 射過程是這樣的:


1、如果C中存在著一個顯式接口成員執行體,該執行體與接口IInterface 及其成員Member相對應,則由它來實現Member 成員。


2、如果條件(1)不滿足,且C中存在著一個非靜態的公有成員,該成員與接口成員Member相對應,則由它來實現Member 成員。


3、如果上述條件仍不滿足,則在類C定義的基類列表中尋找一個C 的基類D,用D來代替C。


4、重復步驟1-- 3 ,遍歷C的所有直接基類和非直接基類,直到找到一個滿足條件的類的成員。


5、如果仍然沒有找到,則報告錯誤。


下面是一個調用基類方法來實現接口成員的例子。類Class2 實現了接口Interface1,類Class2 的基類Class1 的成員也參與了接口的映射,

也就是說類Class2 在對接口Interface1進行實現時,使用了類Class1提供的成員方法F來實現接口Interface1的成員方法F:


interface Interface1 {
void F( ) ;
}
class Class1 {
public void F( ) { }
public void G( ) { }
}
class Class2: Class1, Interface1 {
new public void G( ) {}
}


注意:接口的成員包括它自己定義的成員,而且包括該接口所有父接口定義的成員。在接口映射時,

不僅要對接口定義體中顯式定義的所有成員進行映射,而且要對隱式地從父接口那里繼承來的所有接口成員進行映射。


在進行接口映射時,還要注意下面兩點:


1、在決定由類中的哪個成員來實現接口成員時,類中顯式說明的接口成員比其它成員優先實現。


2、使用Private、protected和static修飾符的成員不能參與實現接口映射。例如:


interface ICloneable {
object Clone( ) ;
}
class C: ICloneable {
object ICloneable.Clone( ) {…}
public object Clone( ) {…}
}


例子中成員ICloneable.Clone 稱為接口ICloneable 的成員Clone 的實現者,因為它是顯式說明的接口成員,

比其它成員有著更高的優先權。


如果一個類實現了兩個或兩個以上名字、類型和參數類型都相同的接口,那么類中的一個成員就可能實現所有這些接口成員:


interface IControl {
void Paint( ) ;
}
interface IForm {
void Paint( ) ;
}
class Page: IControl, IForm {
public void Paint( ) {…}
}


這里,接口IControl和IForm的方法Paint都映射到了類Page中的Paint方法。
當然也可以分別用顯式的接口成員分別實現這兩個方法:


interface IControl {
void Paint( ) ;
}
interface IForm {
void Paint( ) ;
}
class Page: IControl, IForm {
public void IControl.Paint( ) {
//具體的接口實現代碼
}
public void IForm.Paint( ) {
//具體的接口實現代碼
}
}


上面的兩種寫法都是正確的。但是如果接口成員在繼承中覆蓋了父接口的成員,

那么對該接口成員的實現就可能必須映射到顯式接口成員執行體。看下面的例子:


interface IBase {
int P { get; }
}
interface IDerived: IBase {
new int P( ) ;
}


接口IDerived從接口IBase中繼承,這時接口IDerived 的成員方法覆蓋了父接口的成員方法。

因為這時存在著同名的兩個接口成員,那么對這兩個接口成員的實現如果不采用顯式接口成員執行體,

編譯器將無法分辨接口 映射。所以,如果某個類要實現接口IDerived,在類中必須至少定義一個顯式接口成員執行體。

采用下面這些寫法都是合理的:


//一:對兩個接口成員都采用顯式接口成員執行體來實現
lass C: IDerived {
int IBase.P
get
{ //具體的接口實現代碼 }
int IDerived.P( ){
//具體的接口實現代碼 }
}
//二:對Ibase 的接口成員采用顯式接口成員執行體來實現
class C: IDerived {
int IBase.P
get {//具體的接口實現代碼}
public int P( ){
//具體的接口實現代碼 }
}
//三:對IDerived 的接口成員采用顯式接口成員執行體來實現
class C: IDerived{
public int P
get {//具體的接口實現代碼}
int IDerived.P( ){
//具體的接口實現代碼}
}


另一種情況是,如果一個類實現了多個接口,這些接口又擁有同一個父接口,這個父接口只允許被實現一次。


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


上面的例子中,類ComboBox實現了三個接口:IControl,ITextBox和IListBox。
如果認為ComboBox不僅實現了 IControl接口,而且在實現ITextBox和IListBox的同時,
又分別實現了它們的父接口IControl。實際上,對接口 ITextBox 和IListBox 的實現,
分享了對接口IControl 的實現。


我們對C#的接口有了較全面的認識,基本掌握了怎樣應用C#的接口編程,但事實上,
C#的不僅僅應用于.net平臺,它同樣支持以前的COM,可以實現COM類到.NET類的轉換,如C#調用API。
欲了解這方面的知識,請看下一節-接口轉換。
?

?
對于各位使用面向對象編程語言的程序員來說,“接口”這個名詞一定不陌生,

但是不知各位有沒有這樣的疑惑:接口有什么用途?它和抽象類有什么區別?能不能用抽象類代替接口呢?而且,

作為程序員,一定經常聽到“面向接口編程”這個短語,

那么它是什么意思?有什么思想內涵?和面向對象編程是什么關系?本文將一一解答這些疑問。
?
  1.面向接口編程和面向對象編程是什么關系

  首先,面向接口編程和面向對象編程并不是平級的,
它并不是比面向對象編程更先進的一種獨立的編程思想,而是附屬于面向對象思想體系,
屬于其一部分。或者說,它是面向對象編程體系中的思想精髓之一。

  2.接口的本質

  接口,在表面上是由幾個沒有主體代碼的方法定義組成的集合體,有唯一的名稱,
可以被類或其他接口所實現(或者也可以說繼承)。它在形式上可能是如下的樣子:

  

以下是引用片段:
interface InterfaceName
  {
  void Method1();
  void Method2(int para1);
  void Method3(string para2,string para3);
  }
  那么,接口的本質是什么呢?或者說接口存在的意義是什么。我認為可以從以下兩個視角考慮:
  1)接口是一組規則的集合,它規定了實現本接口的類或接口必須擁有的一組規則。
體現了自然界“如果你是……則必須能……”的理念。

  例如,在自然界中,人都能吃飯,即“如果你是人,則必須能吃飯”。
那么模擬到計算機程序中,就應該有一個IPerson(習慣上,接口名由 “I”開頭)接口,
并有一個方法叫Eat(),然后我們規定,每一個表示“人”的類,必須實現IPerson接口,
這就模擬了自然界“如果你是人,則必須能吃飯”這條規則。

  從這里,我想各位也能看到些許面向對象思想的東西。面向對象思想的核心之一,就是模擬真實世界,
把真實世界中的事物抽象成類,整個程序靠各個類的實例互相通信、互相協作完成系統功能,
這非常符合真實世界的運行狀況,也是面向對象思想的精髓。

  2)接口是在一定粒度視圖上同類事物的抽象表示。注意這里我強調了在一定粒度視圖上,
因為“同類事物”這個概念是相對的,它因為粒度視圖不同而不同。

  例如,在我的眼里,我是一個人,和一頭豬有本質區別,我可以接受我和我同學是同類這個說法,
但絕不能接受我和一頭豬是同類。但是,如果在一個動物學家眼里,我和豬應該是同類,因為我們都是動物,
他可以認為“人”和“豬”都實現了IAnimal這個接口,而他在研究動物行為時,不會把我和豬分開對待,
而會從“動物”這個較大的粒度上研究,但他會認為我和一棵樹有本質區別。

  現在換了一個遺傳學家,情況又不同了,因為生物都能遺傳,所以在他眼里,我不僅和豬沒區別,
和一只蚊子、一個細菌、一顆樹、一個蘑菇乃至一個 SARS病毒都沒什么區別,
因為他會認為我們都實現了IDescendable這個接口(注:descend vi. 遺傳),即我們都是可遺傳的東西,
他不會分別研究我們,而會將所有生物作為同類進行研究,在他眼里沒有人和病毒之分,
只有可遺傳的物質和不可遺傳的物質。但至少,我和一塊石頭還是有區別的。

  可不幸的事情發生了,某日,地球上出現了一位偉大的人,他叫列寧,他在熟讀馬克思、
恩格斯的辯證唯物主義思想巨著后,頗有心得,于是他下了一個著名的定義:所謂物質,
就是能被意識所反映的客觀實在。至此,我和一塊石頭、一絲空氣、
一條成語和傳輸手機信號的電磁場已經沒什么區別了,因為在列寧的眼里,
我們都是可以被意識所反映的客觀實在。如果列寧是一名程序員,他會這么說:
所謂物質,就是所有同時實現了“IReflectabe”和“IEsse” 兩個接口的類所生成的實例。
(注:reflect v. 反映 esse n. 客觀實在)

  也許你會覺得我上面的例子像在瞎掰,但是,這正是接口得以存在的意義。
面向對象思想和核心之一叫做多態性,

什么叫多態性?說白了就是在某個粒度視圖層面上對同類事物不加區別的對待而統一處理。

而之所以敢這樣做,就是因為有接口的存在。像那個遺傳學家,他明白所有生物都實現了 IDescendable接口,

那只要是生物,一定有Descend()這個方法,于是他就可以統一研究,而不至于分別研究每一種生物而最終累死。


  可能這里還不能給你一個關于接口本質和作用的直觀印象。那么在后文的例子和對幾個設計模式的解析中,
你將會更直觀體驗到接口的內涵。

  3.面向接口編程綜述

  通過上文,我想大家對接口和接口的思想內涵有了一個了解,那么什么是面向接口編程呢?我個人的定義是:

在系統分析和架構中,分清層次和依賴關系,每個層次不是直接向其上層提供服務(即不是直接實例化在上層中),

而是通過定義一組接口,僅向上層暴露其接口功能,上層對于下層僅僅是接口依賴,而不依賴具體類。


  這樣做的好處是顯而易見的,首先對系統靈活性大有好處。當下層需要改變時,只要接口及接口功能不變
,則上層不用做任何修改。甚至可以在不改動上層代碼時將下層整個替換掉,
就像我們將一個WD的60G硬盤換成一個希捷的160G的硬盤,計算機其他地方不用做任何改動,而是把原硬盤拔下來、
新硬盤插上就行了,因為計算機其他部分不依賴具體硬盤,而只依賴一個IDE接口,
只要硬盤實現了這個接口,就可以替換上去。從這里看,程序中的接口和現實中的接口極為相似,
所以我一直認為,接口(interface)這個詞用的真是神似!

  使用接口的另一個好處就是不同部件或層次的開發人員可以并行開工,就像造硬盤的不用等造CPU的,
也不用等造顯示器的,只要接口一致,設計合理,完全可以并行進行開發,從而提高效率。

  本篇文章先到這里。最后我想再啰嗦一句:面向對象的精髓是模擬現實,這也可以說是我這篇文章的靈魂。
所以,多從現實中思考面向對象的東西,對提高系統分析設計能力大有脾益。

  下篇文章,我將用一個實例來展示接口編程的基本方法。

  而第三篇,我將解析經典設計模式中的一些面向接口編程思想,并解析一下.NET分層架構中的面向接口思想。

  對本文的補充:


  1.關于“面向接口編程”中的“接口”與具體面向對象語言中“接口”兩個詞

  看到有朋友提出“面向接口編程”中的“接口”二字應該比單純編程語言中的interface范圍更大。
我經過思考,覺得很有道理。這里我寫的確實不太合理。我想,面向對象語言中的“接口”是指具體的一種代碼結構
,例如C#中用interface關鍵字定義的接口。而“面向接口編程”中的“接口” 可以說是一種從軟件架構的角度、
從一個更抽象的層面上指那種用于隱藏具體底層類和實現多態性的結構部件。從這個意義上說,
如果定義一個抽象類,并且目的是為了實現多態,那么我認為把這個抽象類也稱為“接口”是合理的。
但是用抽象類實現多態合理不合理?在下面第二條討論。

  概括來說,我覺得兩個“接口”的概念既相互區別又相互聯系。
“面向接口編程”中的接口是一種思想層面的用于實現多態性、提高軟件靈活性和可維護性的架構部件,
而具體語言中的“接口”是將這種思想中的部件具體實施到代碼里的手段。

  2.關于抽象類與接口

  看到回復中這是討論的比較激烈的一個問題。很抱歉我考慮不周沒有在文章中討論這個問題。
我個人對這個問題的理解如下:

  如果單從具體代碼來看,對這兩個概念很容易模糊,甚至覺得接口就是多余的,
因為單從具體功能來看,除多重繼承外(C#,Java中),抽象類似乎完全能取代接口。
但是,難道接口的存在是為了實現多重繼承?當然不是。我認為,抽象類和接口的區別在于使用動機。
使用抽象類是為了代碼的復用,而使用接口的動機是為了實現多態性。所以,
如果你在為某個地方該使用接口還是抽象類而猶豫不決時,那么可以想想你的動機是什么。

  看到有朋友對IPerson這個接口的質疑,我個人的理解是,IPerson這個接口該不該定義,
關鍵看具體應用中是怎么個情況。如果我們的項目中有Women和Man,都繼承Person,
而且Women和Man絕大多數方法都相同,只有一個方法DoSomethingInWC()不同(例子比較粗俗,各位見諒)
,那么當然定義一個AbstractPerson抽象類比較合理,因為它可以把其他所有方法都包含進去,
子類只定義 DoSomethingInWC(),大大減少了重復代碼量。

  但是,如果我們程序中的Women和Man兩個類基本沒有共同代碼,而且有一個PersonHandle類需要實例化他們,
并且不希望知道他們是男是女,而只需把他們當作人看待,并實現多態,那么定義成接口就有必要了。

  總而言之,接口與抽象類的區別主要在于使用的動機,而不在于其本身。
而一個東西該定義成抽象類還是接口,要根據具體環境的上下文決定。

  再者,我認為接口和抽象類的另一個區別在于,抽象類和它的子類之間應該是一般和特殊的關系,
而接口僅僅是它的子類應該實現的一組規則。(當然,有時也可能存在一般與特殊的關系,
但我們使用接口的目的不在這里)如,交通工具定義成抽象類,汽車、飛機、輪船定義成子類,
是可以接受的,因為汽車、飛機、輪船都是一種特殊的交通工具。再譬如Icomparable接口,
它只是說,實現這個接口的類必須要可以進行比較,這是一條規則。如果Car這個類實現了Icomparable,
只是說,我們的Car中有一個方法可以對兩個Car的實例進行比較,可能是比哪輛車更貴,也可能比哪輛車更大,
這都無所謂,但我們不能說“汽車是一種特殊的可以比較”,這在文法上都不通。
?

?

--------------------------------------------------------------------------------

定義:現在我們要開發一個應用,模擬移動存儲設備的讀寫,即計算機與U盤、MP3、移動硬盤等設備進行數據交換。

上下文(環境):已知要實現U盤、MP3播放器、移動硬盤三種移動存儲設備,要求計算機能同這三種設備進行數據交換,
并且以后可能會有新的第三方的移動存儲設備,所以計算機必須有擴展性,
能與目前未知而以后可能會出現的存儲設備進行數據交換。各個存儲設備間讀、寫的實現方法不同,
U盤和移動硬盤只有這兩個方法,MP3Player還有一個PlayMusic方法。

名詞定義:數據交換={讀,寫}

看到上面的問題,我想各位腦子中一定有了不少想法,這是個很好解決的問題,很多方案都能達到效果。
下面,我列舉幾個典型的方案。

解決方案列舉


--------------------------------------------------------------------------------

方案一:分別定義FlashDisk、MP3Player、MobileHardDisk三個類,實現各自的Read和Write方法。
然后在Computer類中實例化上述三個類,為每個類分別寫讀、寫方法。
例如,為FlashDisk寫ReadFromFlashDisk、WriteToFlashDisk兩個方法。總共六個方法。

方案二:定義抽象類MobileStorage,在里面寫虛方法Read和Write,
三個存儲設備繼承此抽象類,并重寫Read和Write方法。
Computer類中包含一個類型為MobileStorage的成員變量,并為其編寫get/set器,
這樣Computer中只需要兩個方法:ReadData和WriteData,并通過多態性實現不同移動設備的讀寫。

方案三:與方案二基本相同,只是不定義抽象類,而是定義接口IMobileStorage,
移動存儲器類實現此接口。Computer中通過依賴接口IMobileStorage實現多態性。

方案四:定義接口IReadable和IWritable,兩個接口分別只包含Read和Write,
然后定義接口IMobileStorage接口繼承自IReadable和IWritable,剩下的實現與方案三相同。

下面,我們來分析一下以上四種方案:

首先,方案一最直白,實現起來最簡單,但是它有一個致命的弱點:可擴展性差。
或者說,不符合“開放-關閉原則”(注:意為對擴展開放,對修改關閉)。
當將來有了第三方擴展移動存儲設備時,必須對Computer進行修改。這就如在一個真實的計算機上,
為每一種移動存儲設備實現一個不同的插口、并分別有各自的驅動程序。當有了一種新的移動存儲設備后,我們就要將計算機大卸八塊,然后增加一個新的插口,在編寫一套針對此新設備的驅動程序。這種設計顯然不可取。

此方案的另一個缺點在于,冗余代碼多。如果有100種移動存儲,
那我們的Computer中豈不是要至少寫200個方法,這是不能接受的!

我們再來看方案二和方案三,之所以將這兩個方案放在一起討論,
是因為他們基本是一個方案(從思想層面上來說),只不過實現手段不同,
一個是使用了抽象類,一個是使用了接口,而且最終達到的目的應該是一樣的。

我們先來評價這種方案:首先它解決了代碼冗余的問題,因為可以動態替換移動設備,
并且都實現了共同的接口,所以不管有多少種移動設備,只要一個Read方法和一個Write方法,
多態性就幫我們解決問題了。而對第一個問題,由于可以運行時動態替換,而不必將移動存儲類硬編碼在Computer中,所以有了新的第三方設備,完全可以替換進去運行。這就是所謂的“依賴接口,而不是依賴與具體類”,不信你看看,Computer類只有一個MobileStorage類型或IMobileStorage類型的成員變量,至于這個變量具體是什么類型,它并不知道,這取決于我們在運行時給這個變量的賦值。如此一來,Computer和移動存儲器類的耦合度大大下降。

那么這里該選抽象類還是接口呢?還記得第一篇文章我對抽象類和接口選擇的建議嗎?看動機。
這里,我們的動機顯然是實現多態性而不是為了代碼復用,所以當然要用接口。

最后我們再來看一看方案四,它和方案三很類似,只是將“可讀”和“可寫”兩個規則分別抽象成了接口,
然后讓IMobileStorage再繼承它們。這樣做,顯然進一步提高了靈活性,但是,這有沒有設計過度的嫌疑呢?
我的觀點是:這要看具體情況。如果我們的應用中可能會出現一些類,這些類只實現讀方法或只實現寫方法,
如只讀光盤,那么這樣做也是可以的。如果我們知道以后出現的東西都是能讀又能寫的,
那這兩個接口就沒有必要了。其實如果將只讀設備的Write方法留空或拋出異常,也可以不要這兩個接口。

總之一句話:理論是死的,人是活的,一切從現實需要來,防止設計不足,也要防止設計過度。

在這里,我們姑且認為以后的移動存儲都是能讀又能寫的,所以我們選方案三。

實現


--------------------------------------------------------------------------------

下面,我們要將解決方案加以實現。我選擇的語言是C#,但是在代碼中不會用到C#特有的性質,
所以使用其他語言的朋友一樣可以參考。

首先編寫IMobileStorage接口:

Code:IMobileStorage

1namespace InterfaceExample
2{
3??? public interface IMobileStorage
4??? {
5??????? void Read();//從自身讀數據
6??????? void Write();//將數據寫入自身
7??? }
8}

代碼比較簡單,只有兩個方法,沒什么好說的,接下來是三個移動存儲設備的具體實現代碼:

U盤

Code:FlashDisk

1namespace InterfaceExample
2{
3??? public class FlashDisk : IMobileStorage
4??? {
5??????? public void Read()
6??????? {
7??????????? Console.WriteLine("Reading from FlashDisk……");
8??????????? Console.WriteLine("Read finished!");
9??????? }
10
11??????? public void Write()
12??????? {
13??????????? Console.WriteLine("Writing to FlashDisk……");
14??????????? Console.WriteLine("Write finished!");
15??????? }
16??? }
17}
MP3

Code:MP3Player

1namespace InterfaceExample
2{
3??? public class MP3Player : IMobileStorage
4??? {
5??????? public void Read()
6??????? {
7??????????? Console.WriteLine("Reading from MP3Player……");
8??????????? Console.WriteLine("Read finished!");
9??????? }
10
11??????? public void Write()
12??????? {
13??????????? Console.WriteLine("Writing to MP3Player……");
14??????????? Console.WriteLine("Write finished!");
15??????? }
16
17??????? public void PlayMusic()
18??????? {
19??????????? Console.WriteLine("Music is playing……");
20??????? }
21??? }
22}
移動硬盤

Code:MobileHardDisk

1namespace InterfaceExample
2{
3??? public class MobileHardDisk : IMobileStorage
4??? {
5??????? public void Read()
6??????? {
7??????????? Console.WriteLine("Reading from MobileHardDisk……");
8??????????? Console.WriteLine("Read finished!");
9??????? }
10
11??????? public void Write()
12??????? {
13??????????? Console.WriteLine("Writing to MobileHardDisk……");
14??????????? Console.WriteLine("Write finished!");
15??????? }
16??? }
17}
可以看到,它們都實現了IMobileStorage接口,并重寫了各自不同的Read和Write方法。
下面,我們來寫Computer:

Code:Computer

1namespace InterfaceExample
2{
3??? public class Computer
4??? {
5??????? private IMobileStorage _usbDrive;
6
7??????? public IMobileStorage UsbDrive
8??????? {
9??????????? get
10??????????? {
11??????????????? return this._usbDrive;
12??????????? }
13??????????? set
14??????????? {
15??????????????? this._usbDrive = value;
16??????????? }
17??????? }
18
19??????? public Computer()
20??????? {
21??????? }
22
23??????? public Computer(IMobileStorage usbDrive)
24??????? {
25??????????? this.UsbDrive = usbDrive;
26??????? }
27???
28??????? public void ReadData()
29??????? {
30??????????? this._usbDrive.Read();
31??????? }
32
33??????? public void WriteData()
34??????? {
35??????????? this._usbDrive.Write();
36??????? }
37??? }
38}
其中的UsbDrive就是可替換的移動存儲設備,之所以用這個名字,是為了讓大家覺得直觀,
就像我們平常使用電腦上的USB插口插拔設備一樣。

OK!下面我們來測試我們的“電腦”和“移動存儲設備”是否工作正常。
我是用的C#控制臺程序,具體代碼如下:

Code:測試代碼

1namespace InterfaceExample
2{
3??? class Program
4??? {
5??????? static void Main(string[] args)
6??????? {
7??????????? Computer computer = new Computer();
8??????????? IMobileStorage mp3Player = new MP3Player();
9??????????? IMobileStorage flashDisk = new FlashDisk();
10??????????? IMobileStorage mobileHardDisk = new MobileHardDisk();
11
12??????????? Console.WriteLine("I inserted my MP3 Player into my computer and copy some music to it:");
13??????????? computer.UsbDrive = mp3Player;
14??????????? computer.WriteData();
15??????????? Console.WriteLine();
16
17??????????? Console.WriteLine("Well,I also want to copy a great movie to my computer from a mobile hard disk:");
18??????????? computer.UsbDrive = mobileHardDisk;
19??????????? computer.ReadData();
20??????????? Console.WriteLine();
21
22??????????? Console.WriteLine("OK!I have to read some files from my flash disk and copy another file to it:");
23??????????? computer.UsbDrive = flashDisk;
24??????????? computer.ReadData();
25??????????? computer.WriteData();
26??????????? Console.ReadLine();
27??????? }
28??? }
29}
現在編譯、運行程序,如果沒有問題,將看到如下運行結果:

?


圖2.1 各種移動存儲設備測試結果

好的,看來我們的系統工作良好。

后來……


--------------------------------------------------------------------------------


剛過了一個星期,就有人送來了新的移動存儲設備NewMobileStorage,讓我測試能不能用,我微微一笑,
心想這不是小菜一碟,讓我們看看面向接口編程的威力吧!將測試程序修改成如下:

Code:測試代碼

1namespace InterfaceExample
2{
3??? class Program
4??? {
5??????? static void Main(string[] args)
6??????? {
7??????????? Computer computer = new Computer();
8??????????? IMobileStorage newMobileStorage = new NewMobileStorage();
9
10??????????? Console.WriteLine("Now,I am testing the new mobile storage:");
11??????????? computer.UsbDrive = newMobileStorage;
12??????????? computer.ReadData();
13??????????? computer.WriteData();
14??????????? Console.ReadLine();
15??????? }
16??? }
17}
編譯、運行、看結果:

哈哈,神奇吧,Computer一點都不用改動,就可以使新的設備正常運行。這就是所謂“對擴展開放,對修改關閉”。

?

圖2.2 新設備擴展測試結果

又過了幾天,有人通知我說又有一個叫SuperStorage的移動設備要接到我們的Computer上,
我心想來吧,管你是“超級存儲”還是“特級存儲”,我的“面向接口編程大法”把你們統統搞定。

但是,當設備真的送來,我傻眼了,開發這個新設備的團隊沒有拿到我們的IMobileStorage接口,
自然也沒有遵照這個約定。這個設備的讀、寫方法不叫Read和Write,而是叫rd和wt,
這下完了……不符合接口啊,插不上。但是,不要著急,我們回到現實來找找解決的辦法。
我們一起想想:如果你的Computer上只有USB接口,而有人拿來一個PS/2的鼠標要插上用,你該怎么辦?
想起來了吧,是不是有一種叫“PS/2-USB”轉換器的東西?也叫適配器,可以進行不同接口的轉換。
對了!程序中也有轉換器。

這里,我要引入一個設計模式,叫“Adapter”。它的作用就如現實中的適配器一樣,
把接口不一致的兩個插件接合起來。由于本篇不是講設計模式的,而且Adapter設計模式很好理解,
所以我就不細講了,先來看我設計的類圖吧:

如圖所示,雖然SuperStorage沒有實現IMobileStorage,但我們定義了一個實現IMobileStorage的SuperStorageAdapter,
它聚合了一個SuperStorage,并將rd和wt適配為Read和Write,SuperStorageAdapter

?

圖2.3 Adapter模式應用示意

具體代碼如下:

Code:SuperStorageAdapter

1namespace InterfaceExample
2{
3??? public class SuperStorageAdapter : IMobileStorage
4??? {
5??????? private SuperStorage _superStorage;
6
7??????? public SuperStorage SuperStorage
8??????? {
9??????????? get
10??????????? {
11??????????????? return this._superStorage;
12??????????? }
13??????????? set
14??????????? {
15??????????????? this._superStorage = value;
16??????????? }
17??????? }
18???
19??????? public void Read()
20??????? {
21??????????? this._superStorage.rd();
22??????? }
23
24??????? public void Write()
25??????? {
26??????????? this._superStorage.wt();
27??????? }
28??? }
29}
好,現在我們來測試適配過的新設備,測試代碼如下:

Code:測試代碼

1namespace InterfaceExample
2{
3??? class Program
4??? {
5??????? static void Main(string[] args)
6??????? {
7??????????? Computer computer = new Computer();
8??????????? SuperStorageAdapter superStorageAdapter = new SuperStorageAdapter();
9??????????? SuperStorage superStorage = new SuperStorage();
10??????????? superStorageAdapter.SuperStorage = superStorage;
11
12??????????? Console.WriteLine("Now,I am testing the new super storage with adapter:");
13??????????? computer.UsbDrive = superStorageAdapter;
14??????????? computer.ReadData();
15??????????? computer.WriteData();
16??????????? Console.ReadLine();
17??????? }
18??? }
19}
運行后會得到如下結果:

?

圖2.4 利用Adapter模式運行新設備測試結果

OK!雖然遇到了一些困難,不過在設計模式的幫助下,我們還是在沒有修改Computer任何代碼的情況下實現了新設備的運行。

好了,理論在第一篇講得足夠多了,所以這里我就不多講了。希望各位朋友結合第一篇的理論和這個例子,仔細思考面向接口的問題。當然,不要忘了結合現實。


?
???
自動化(Automation)基礎概念:二次開發接口(API)與插件(Addin) 2009-07-06 00:53 在前文,我們已經解釋了:
自動化(Automation)基礎概念:COM組件(Component)與接口(Interface)
自動化(Automation)基礎概念:變體(Variant)與Dispatch調用(IDispatch)
而同時,我們經常也可能經常聽到以下這些詞語:
自動化(Automation,COM Automation) OA(辦公自動化,Office Automation)

?二次開發接口(應用程序開發接口,Application Programming Interface,API) 插件(Addin,Addon) 等等。
本文試圖解釋這些概念。
自動化(Automation)顧名思義是指“讓機器在沒有人工干預的情況下自動完成特定的任務”。

為了完成這一目標,自動化(Automation)技術的核心想法是,應用程序(Application)

需要把自己的核心功能以DOM模型的形式對外提供,使得別人能夠通過這個DOM模型來使用該應用程序的功能。

這也就是我們通常說的應用程序編程接口——Application Programming Interface,簡稱API。

為了與Windows API這樣的編程接口區分開來,我們引入一個專有名詞,叫“二次開發接口”。

“二次開發”取意于“在現有應用程序基礎上進行再開發”。其實如果你愿意把操作系統當作一個更大的應用程序的話,

二次開發接口和Windows API并沒有什么很大的本質上的差異(盡管我們知道Windows API并不是以COM組件方式提供的)。
?
理解了自動化(Automation),OA(辦公自動化,Office Automation)就比較好解釋,無非是應用程序特指辦公軟件而已。
而OA是指辦公(包括公文流轉)系統的自動化。
在應用程序提供了編程接口(API)的前提下,典型情況下,我們有兩種辦法來使用這些API。

方法一是把應用程序當作一個Server,通過API對外提供服務。在此情形下,應用程序只是作為一個EXE COM Server的服務程序而已。

只要我們理解進程間的LPC或者RPC調用是怎么回事,那么一切就非常Easy。方法二是實現一個應用程序插件(Addin)。

這種方法更有意思一些。首先,這是一種進程內的調用,效率非常好。其次,這是一種雙向的通訊,

應用程序通過它提供的插件機制感知到插件的存在,并且將插件加載上來;插件則是在獲得活動權后,

通過應用程序的API完成特定的功能。最后,也是最重要的,插件與應用程序融為一體,實際上是擴展了應用程序的能力,

使得應用程序變得更為強大。
插件(Addins)的啟動過程大體如下:
?
應用程序啟動。通過注冊表(或者存放于其他任何地方)獲得插件列表。插件一般以 COM 組件形式提供,

故此只要有一個插件的 CLSID 或者 ProgID 的列表就可以了。另外,插件的功能可以千差萬別,

但是他們需要統一實現一個接口,例如 _IDTExtensibility2 或者類似的東西。這個接口在下面的第二步就用到了。

遍歷插件列表,創建并初始化各插件。關鍵是初始化。當然應用程序并不知道插件想做什么,

它只是取得 _IDTExtensibility2(或者類似接口),調用其中的初始化函數(如 OnConnection)。

插件獲得了初始化機會。注意,在初始化的時候,應用程序把自己的DOM模型的根接口(我們通常稱為Application)傳入。

在 _IDTExtensibility2 中,根接口被定義為 IDispatch 類型,即 IDispatch* Application。

但是實際上可以更通用,如IUnknown* Application。有了這個 Application 指針,插件就可以為所欲為,

做它想做的事情,調用它想要調用的任何API。 從插件(Addins)展開來講,可以講非常多的內容。然而這不是本文的意圖。

所以關于這方面的內容,我們只能留待以后有機會繼續這個話題。不過我還是忍不住把話題起個開頭:

由于插件(Addin)機制使得應用程序結構顯得更為靈活,所以,越來越多的軟件架構,

追求一種超輕量的內核(也就是我們說的應用程序,之所以稱為內核,是因為它是組織一切的核心),

并把更多的功能通過插件(Addin)方式提供。超輕量的內核意味著需要解決一個額外的關鍵點:

就是插件(Addin)不只是擴展應用程序的功能,也同時擴展了應用程序的API,這些API與原有內核的API無縫地結合在一起,

從而使得整個系統可以滾雪球一樣越滾越大。?


?

轉載于:https://www.cnblogs.com/lanbaoming/archive/2011/11/15/2249937.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的什么事接口的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

午夜福利试看120秒体验区 | 久久www免费人成人片 | 亚洲国产精品无码久久久久高潮 | 丰满少妇女裸体bbw | 国产无遮挡吃胸膜奶免费看 | 最近中文2019字幕第二页 | 亚洲国产一区二区三区在线观看 | 欧美日韩视频无码一区二区三 | 国产精品久久精品三级 | 久久亚洲精品成人无码 | 中文字幕日产无线码一区 | 人妻无码久久精品人妻 | 国产精品国产自线拍免费软件 | 国产精品无码mv在线观看 | 丰满肥臀大屁股熟妇激情视频 | 久久久久人妻一区精品色欧美 | 1000部啪啪未满十八勿入下载 | 亚洲人成影院在线无码按摩店 | 国产日产欧产精品精品app | 亚洲一区二区三区四区 | 久久天天躁狠狠躁夜夜免费观看 | 无码人妻丰满熟妇区毛片18 | 色欲久久久天天天综合网精品 | 免费无码一区二区三区蜜桃大 | av无码电影一区二区三区 | 一本色道久久综合亚洲精品不卡 | 免费无码av一区二区 | 久久国产精品二国产精品 | 中文字幕无码日韩欧毛 | 国产无遮挡又黄又爽又色 | 嫩b人妻精品一区二区三区 | 国产内射爽爽大片视频社区在线 | 爱做久久久久久 | 国产成人精品无码播放 | 中文字幕+乱码+中文字幕一区 | 国产精品多人p群无码 | 性色欲网站人妻丰满中文久久不卡 | 婷婷丁香五月天综合东京热 | 爆乳一区二区三区无码 | 内射白嫩少妇超碰 | а√资源新版在线天堂 | 国产香蕉97碰碰久久人人 | 婷婷五月综合缴情在线视频 | 狂野欧美性猛xxxx乱大交 | 四虎国产精品一区二区 | 久久人人爽人人人人片 | 又粗又大又硬毛片免费看 | 久久国产精品二国产精品 | 一本大道久久东京热无码av | 午夜福利不卡在线视频 | 欧美人与物videos另类 | 色欲综合久久中文字幕网 | 免费观看激色视频网站 | 亚洲毛片av日韩av无码 | 国产精品亚洲综合色区韩国 | 亚无码乱人伦一区二区 | 亚洲综合无码久久精品综合 | 永久免费观看国产裸体美女 | 国产绳艺sm调教室论坛 | 少妇被黑人到高潮喷出白浆 | 免费观看又污又黄的网站 | 天海翼激烈高潮到腰振不止 | 精品久久久久久人妻无码中文字幕 | 高潮毛片无遮挡高清免费 | 少女韩国电视剧在线观看完整 | 性欧美熟妇videofreesex | 国产成人精品无码播放 | 又大又硬又爽免费视频 | 日日摸天天摸爽爽狠狠97 | 国产成人久久精品流白浆 | 人妻少妇精品无码专区动漫 | 丰满人妻精品国产99aⅴ | 精品 日韩 国产 欧美 视频 | 大色综合色综合网站 | 动漫av一区二区在线观看 | 日本熟妇大屁股人妻 | 欧洲vodafone精品性 | 久久综合九色综合欧美狠狠 | 一区二区三区高清视频一 | 思思久久99热只有频精品66 | 国精产品一区二区三区 | 免费无码一区二区三区蜜桃大 | 麻豆国产丝袜白领秘书在线观看 | 色综合天天综合狠狠爱 | 扒开双腿疯狂进出爽爽爽视频 | 亚洲精品欧美二区三区中文字幕 | 国产 浪潮av性色四虎 | 久久99国产综合精品 | 极品嫩模高潮叫床 | 日韩精品a片一区二区三区妖精 | 九一九色国产 | 欧美人与牲动交xxxx | 人妻无码久久精品人妻 | 国产三级精品三级男人的天堂 | 国产亚洲精品久久久久久久 | 久久国产36精品色熟妇 | 无码人妻出轨黑人中文字幕 | 狠狠色欧美亚洲狠狠色www | 亚洲乱码国产乱码精品精 | 中文无码伦av中文字幕 | 日欧一片内射va在线影院 | 久久久久国色av免费观看性色 | 国产sm调教视频在线观看 | 欧美国产日韩亚洲中文 | 青草视频在线播放 | 亚洲爆乳无码专区 | 国产精品爱久久久久久久 | 99久久精品日本一区二区免费 | 亚洲国产精品无码一区二区三区 | 一本大道久久东京热无码av | 偷窥村妇洗澡毛毛多 | 成人亚洲精品久久久久软件 | 中文字幕日韩精品一区二区三区 | 色欲av亚洲一区无码少妇 | 亚洲成av人片在线观看无码不卡 | 午夜不卡av免费 一本久久a久久精品vr综合 | 久久国产精品偷任你爽任你 | 国产绳艺sm调教室论坛 | 国产情侣作爱视频免费观看 | 亚洲国产精品久久久天堂 | 久久国产精品_国产精品 | 亚洲欧美综合区丁香五月小说 | 久久精品国产99精品亚洲 | 久久天天躁狠狠躁夜夜免费观看 | 国产超碰人人爽人人做人人添 | 秋霞成人午夜鲁丝一区二区三区 | 成人试看120秒体验区 | 久久精品国产大片免费观看 | 超碰97人人做人人爱少妇 | 一本久久a久久精品亚洲 | 丝袜人妻一区二区三区 | 国产精品爱久久久久久久 | 日日碰狠狠躁久久躁蜜桃 | 亚洲中文字幕无码一久久区 | 欧美freesex黑人又粗又大 | 精品国产国产综合精品 | 台湾无码一区二区 | 男女爱爱好爽视频免费看 | 久久久精品国产sm最大网站 | 九九热爱视频精品 | 精品无码国产自产拍在线观看蜜 | 香港三级日本三级妇三级 | 亚洲日韩av一区二区三区中文 | 国产深夜福利视频在线 | 未满小14洗澡无码视频网站 | 97资源共享在线视频 | 久久精品视频在线看15 | 久久综合香蕉国产蜜臀av | 人人澡人人妻人人爽人人蜜桃 | 无遮挡国产高潮视频免费观看 | 精品国产av色一区二区深夜久久 | 东京无码熟妇人妻av在线网址 | 亚洲一区二区三区含羞草 | 欧洲熟妇色 欧美 | 亚洲日韩av一区二区三区四区 | 午夜福利试看120秒体验区 | 精品乱子伦一区二区三区 | 久久久久av无码免费网 | 国产麻豆精品精东影业av网站 | 曰本女人与公拘交酡免费视频 | 爆乳一区二区三区无码 | 日韩在线不卡免费视频一区 | 欧美刺激性大交 | 日本熟妇大屁股人妻 | 久久久久成人片免费观看蜜芽 | 少妇愉情理伦片bd | 欧美性猛交xxxx富婆 | 动漫av一区二区在线观看 | 久久国产精品萌白酱免费 | 国产真实夫妇视频 | 乱码av麻豆丝袜熟女系列 | 日本高清一区免费中文视频 | 久久久久久久久888 | 国产精品美女久久久久av爽李琼 | 成人欧美一区二区三区黑人免费 | 日韩av无码一区二区三区 | 欧美激情内射喷水高潮 | 国产一区二区三区日韩精品 | 久久99精品国产麻豆 | 性欧美大战久久久久久久 | 综合网日日天干夜夜久久 | 日韩精品成人一区二区三区 | 中文字幕无码日韩专区 | 76少妇精品导航 | 久久久成人毛片无码 | 中文字幕无码日韩专区 | 亚洲日韩av一区二区三区四区 | 国产激情精品一区二区三区 | 婷婷丁香五月天综合东京热 | 国产性生交xxxxx无码 | 国语自产偷拍精品视频偷 | 国产热a欧美热a在线视频 | 国产热a欧美热a在线视频 | 女人被男人爽到呻吟的视频 | 国产成人精品久久亚洲高清不卡 | 国产热a欧美热a在线视频 | 亚洲精品午夜国产va久久成人 | 亚洲高清偷拍一区二区三区 | 亚洲色欲色欲欲www在线 | 国产黄在线观看免费观看不卡 | 性欧美疯狂xxxxbbbb | 极品嫩模高潮叫床 | 久久天天躁夜夜躁狠狠 | aⅴ亚洲 日韩 色 图网站 播放 | 国模大胆一区二区三区 | 牲交欧美兽交欧美 | 日日躁夜夜躁狠狠躁 | 亚洲成熟女人毛毛耸耸多 | 国产深夜福利视频在线 | 中文字幕乱码人妻二区三区 | 人人澡人人妻人人爽人人蜜桃 | 国产精品亚洲а∨无码播放麻豆 | 亚洲日韩一区二区 | 丰满人妻精品国产99aⅴ | 99国产欧美久久久精品 | a在线观看免费网站大全 | 久久亚洲精品中文字幕无男同 | 国产精品鲁鲁鲁 | 熟妇人妻激情偷爽文 | 精品国产一区二区三区四区在线看 | 中文字幕无线码免费人妻 | 日本一区二区更新不卡 | 久久午夜无码鲁丝片秋霞 | 国产精品美女久久久 | 国产内射爽爽大片视频社区在线 | 动漫av一区二区在线观看 | 帮老师解开蕾丝奶罩吸乳网站 | 捆绑白丝粉色jk震动捧喷白浆 | 一本色道久久综合亚洲精品不卡 | 精品久久综合1区2区3区激情 | 免费人成网站视频在线观看 | 少妇邻居内射在线 | 亚洲理论电影在线观看 | 天天摸天天透天天添 | 日本va欧美va欧美va精品 | 午夜精品久久久久久久久 | 国产激情无码一区二区app | 中文字幕av伊人av无码av | 青青青手机频在线观看 | 天干天干啦夜天干天2017 | 国精产品一品二品国精品69xx | 又湿又紧又大又爽a视频国产 | 97人妻精品一区二区三区 | 强奷人妻日本中文字幕 | 国产精品va在线播放 | 欧洲精品码一区二区三区免费看 | 精品一区二区三区波多野结衣 | 人人爽人人爽人人片av亚洲 | 亚洲人成影院在线观看 | 亚洲日本va午夜在线电影 | 国产成人无码av在线影院 | 香蕉久久久久久av成人 | 欧美老妇与禽交 | 国产精品亚洲五月天高清 | 成熟妇人a片免费看网站 | 国内精品人妻无码久久久影院 | 亚洲午夜福利在线观看 | 少妇邻居内射在线 | 日产精品高潮呻吟av久久 | 久久亚洲精品成人无码 | 欧美一区二区三区 | 少妇高潮一区二区三区99 | 人妻少妇被猛烈进入中文字幕 | 日日摸天天摸爽爽狠狠97 | 天干天干啦夜天干天2017 | 东京一本一道一二三区 | 宝宝好涨水快流出来免费视频 | 色婷婷香蕉在线一区二区 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 国内精品人妻无码久久久影院蜜桃 | 国产人妻精品一区二区三区 | 中文字幕人妻丝袜二区 | 亚洲精品综合五月久久小说 | 免费国产黄网站在线观看 | 黄网在线观看免费网站 | 亚洲の无码国产の无码步美 | 无码人妻丰满熟妇区五十路百度 | 熟妇激情内射com | 日韩欧美群交p片內射中文 | 欧美激情内射喷水高潮 | 久久午夜无码鲁丝片秋霞 | 夜夜躁日日躁狠狠久久av | 性色av无码免费一区二区三区 | 国内少妇偷人精品视频免费 | 性欧美牲交xxxxx视频 | 国产av无码专区亚洲awww | 免费无码一区二区三区蜜桃大 | 国产精品福利视频导航 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 日本大乳高潮视频在线观看 | 精品久久久久香蕉网 | 亚洲日韩精品欧美一区二区 | 久久精品国产精品国产精品污 | 国产无av码在线观看 | 美女扒开屁股让男人桶 | 欧美 亚洲 国产 另类 | 久久精品国产日本波多野结衣 | 嫩b人妻精品一区二区三区 | 青青草原综合久久大伊人精品 | 欧美日韩一区二区综合 | 少妇邻居内射在线 | 激情五月综合色婷婷一区二区 | 领导边摸边吃奶边做爽在线观看 | 国产精品多人p群无码 | 特级做a爰片毛片免费69 | 欧美性猛交内射兽交老熟妇 | 国产麻豆精品一区二区三区v视界 | 一二三四社区在线中文视频 | 97色伦图片97综合影院 | 国产特级毛片aaaaaaa高清 | 少妇性俱乐部纵欲狂欢电影 | 中文字幕av伊人av无码av | 亚洲一区二区三区含羞草 | 国产一区二区三区影院 | 成人aaa片一区国产精品 | 国产片av国语在线观看 | 国产成人久久精品流白浆 | 久热国产vs视频在线观看 | 一本色道婷婷久久欧美 | 国产舌乚八伦偷品w中 | 国产精品亚洲а∨无码播放麻豆 | 亚洲精品无码人妻无码 | 丰满人妻一区二区三区免费视频 | 亚洲熟悉妇女xxx妇女av | 日本成熟视频免费视频 | 亚洲成a人片在线观看无码 | 国产xxx69麻豆国语对白 | 国产激情无码一区二区 | 精品aⅴ一区二区三区 | 色婷婷综合激情综在线播放 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 丰满人妻一区二区三区免费视频 | 日本精品高清一区二区 | 久久亚洲国产成人精品性色 | 久久精品国产大片免费观看 | 伦伦影院午夜理论片 | 久久久婷婷五月亚洲97号色 | 偷窥村妇洗澡毛毛多 | 免费无码一区二区三区蜜桃大 | 东京热一精品无码av | 日本熟妇大屁股人妻 | 色 综合 欧美 亚洲 国产 | 国产精品第一国产精品 | 日本精品久久久久中文字幕 | 国产熟妇另类久久久久 | 国产激情综合五月久久 | 欧美freesex黑人又粗又大 | 最新版天堂资源中文官网 | 乱人伦中文视频在线观看 | 精品国产av色一区二区深夜久久 | 亚洲欧美日韩综合久久久 | 少妇的肉体aa片免费 | 日韩少妇内射免费播放 | 国产精品亚洲五月天高清 | 亚洲爆乳精品无码一区二区三区 | 亚洲成色www久久网站 | 一本无码人妻在中文字幕免费 | 国产人妻精品一区二区三区不卡 | 日本护士xxxxhd少妇 | 国产另类ts人妖一区二区 | 中文字幕乱码人妻二区三区 | 欧洲熟妇精品视频 | 国产美女极度色诱视频www | 亚洲中文字幕乱码av波多ji | 永久黄网站色视频免费直播 | 日韩人妻无码一区二区三区久久99 | 久久久国产精品无码免费专区 | 亚洲精品一区二区三区大桥未久 | 欧美一区二区三区 | 国产亚洲tv在线观看 | 99精品国产综合久久久久五月天 | 亚洲日韩精品欧美一区二区 | 免费人成网站视频在线观看 | 内射白嫩少妇超碰 | 亚洲の无码国产の无码影院 | 日韩少妇内射免费播放 | 美女张开腿让人桶 | 亚洲人成网站在线播放942 | 水蜜桃亚洲一二三四在线 | 极品嫩模高潮叫床 | 黑人巨大精品欧美一区二区 | 中文字幕中文有码在线 | 熟妇女人妻丰满少妇中文字幕 | 无码人中文字幕 | 日本精品久久久久中文字幕 | 成人欧美一区二区三区黑人免费 | 2020久久超碰国产精品最新 | 一本精品99久久精品77 | 成人片黄网站色大片免费观看 | 人妻无码αv中文字幕久久琪琪布 | 中文字幕无码免费久久99 | 图片区 小说区 区 亚洲五月 | 日产精品高潮呻吟av久久 | 性欧美熟妇videofreesex | 国产香蕉尹人综合在线观看 | 日本精品少妇一区二区三区 | 亚洲人成网站在线播放942 | 亚洲熟妇色xxxxx欧美老妇y | 综合人妻久久一区二区精品 | 无码一区二区三区在线观看 | 一个人看的www免费视频在线观看 | 欧美阿v高清资源不卡在线播放 | 欧美精品免费观看二区 | 亚洲一区二区三区国产精华液 | 亚洲日韩乱码中文无码蜜桃臀网站 | 亚洲成色www久久网站 | 乱码午夜-极国产极内射 | 人妻体内射精一区二区三四 | 丁香啪啪综合成人亚洲 | 中文字幕色婷婷在线视频 | 国产成人精品一区二区在线小狼 | 国产片av国语在线观看 | 亚洲精品无码国产 | 久久久久免费精品国产 | 国内精品久久久久久中文字幕 | 狠狠色色综合网站 | 久久精品人人做人人综合 | 精品国产一区二区三区四区 | 老熟妇仑乱视频一区二区 | 久久综合网欧美色妞网 | 成人综合网亚洲伊人 | 国产精品无码mv在线观看 | 少妇被粗大的猛进出69影院 | 成人精品视频一区二区三区尤物 | 日韩欧美群交p片內射中文 | 无码吃奶揉捏奶头高潮视频 | 精品欧美一区二区三区久久久 | 蜜桃视频韩日免费播放 | 综合网日日天干夜夜久久 | 性生交大片免费看女人按摩摩 | 老太婆性杂交欧美肥老太 | 国内少妇偷人精品视频 | 中文字幕乱妇无码av在线 | 人妻中文无码久热丝袜 | 巨爆乳无码视频在线观看 | 亚洲日韩av一区二区三区中文 | 无码免费一区二区三区 | 蜜臀av无码人妻精品 | 亚洲日韩一区二区三区 | 网友自拍区视频精品 | 亚洲第一网站男人都懂 | 台湾无码一区二区 | 一本大道久久东京热无码av | 国产三级精品三级男人的天堂 | 亚洲区小说区激情区图片区 | 麻花豆传媒剧国产免费mv在线 | 国产亚洲精品久久久久久 | 大肉大捧一进一出好爽视频 | 久久zyz资源站无码中文动漫 | 欧美丰满熟妇xxxx性ppx人交 | 久久天天躁狠狠躁夜夜免费观看 | 天天拍夜夜添久久精品 | 亚洲中文字幕无码中文字在线 | 5858s亚洲色大成网站www | 亚洲中文字幕av在天堂 | 免费观看的无遮挡av | 麻豆蜜桃av蜜臀av色欲av | 亚洲人亚洲人成电影网站色 | 内射爽无广熟女亚洲 | 国产亚洲欧美在线专区 | 色综合久久久久综合一本到桃花网 | 国产精品久久久久9999小说 | 中文精品无码中文字幕无码专区 | 97色伦图片97综合影院 | 狂野欧美激情性xxxx | 中文字幕人妻无码一区二区三区 | 少妇邻居内射在线 | 久久熟妇人妻午夜寂寞影院 | 午夜不卡av免费 一本久久a久久精品vr综合 | 国产片av国语在线观看 | 亚洲国产av美女网站 | 强伦人妻一区二区三区视频18 | 亚洲va欧美va天堂v国产综合 | 俺去俺来也www色官网 | 久久精品一区二区三区四区 | 国产亚洲精品久久久久久久久动漫 | 亚洲精品久久久久久久久久久 | 国产又爽又黄又刺激的视频 | 亚洲日本va中文字幕 | 少妇厨房愉情理9仑片视频 | 中文毛片无遮挡高清免费 | 欧洲欧美人成视频在线 | 亚洲男人av天堂午夜在 | 亚洲a无码综合a国产av中文 | 国产熟女一区二区三区四区五区 | 欧美激情内射喷水高潮 | 中文字幕 亚洲精品 第1页 | 中文字幕av伊人av无码av | 真人与拘做受免费视频一 | 无码人妻少妇伦在线电影 | 久久久av男人的天堂 | 人人爽人人爽人人片av亚洲 | 麻豆国产人妻欲求不满谁演的 | 亚洲精品无码人妻无码 | 自拍偷自拍亚洲精品10p | 九一九色国产 | 红桃av一区二区三区在线无码av | 午夜福利一区二区三区在线观看 | 精品久久综合1区2区3区激情 | 天堂а√在线地址中文在线 | 俺去俺来也在线www色官网 | 亚洲色欲色欲欲www在线 | 少妇厨房愉情理9仑片视频 | 初尝人妻少妇中文字幕 | 香蕉久久久久久av成人 | 无码人妻av免费一区二区三区 | 色婷婷av一区二区三区之红樱桃 | 啦啦啦www在线观看免费视频 | 欧美日韩一区二区综合 | 在线天堂新版最新版在线8 | 国产欧美亚洲精品a | 熟女少妇在线视频播放 | 国产精品无码成人午夜电影 | 十八禁真人啪啪免费网站 | 国产欧美精品一区二区三区 | 国产精品爱久久久久久久 | 国产绳艺sm调教室论坛 | 国产成人午夜福利在线播放 | 天天爽夜夜爽夜夜爽 | 国产乡下妇女做爰 | 真人与拘做受免费视频 | 亚洲成在人网站无码天堂 | 人妻体内射精一区二区三四 | 亚洲中文字幕av在天堂 | 国产精品丝袜黑色高跟鞋 | 国产成人精品一区二区在线小狼 | 国产成人无码a区在线观看视频app | 成人一在线视频日韩国产 | 日本精品人妻无码免费大全 | 欧美阿v高清资源不卡在线播放 | 一本久久伊人热热精品中文字幕 | 波多野结衣av一区二区全免费观看 | 国产在线精品一区二区高清不卡 | 久久亚洲中文字幕精品一区 | 一本久久伊人热热精品中文字幕 | 亚洲男人av天堂午夜在 | 最近中文2019字幕第二页 | 国产精品怡红院永久免费 | 麻花豆传媒剧国产免费mv在线 | 久久精品国产日本波多野结衣 | 欧美国产亚洲日韩在线二区 | 人人妻人人澡人人爽人人精品浪潮 | 欧美日韩一区二区免费视频 | 国产成人精品三级麻豆 | 欧美日韩精品 | 亚洲中文字幕在线观看 | 麻豆精品国产精华精华液好用吗 | 国产明星裸体无码xxxx视频 | 欧美性生交活xxxxxdddd | 久久久久久久女国产乱让韩 | 综合激情五月综合激情五月激情1 | 国产免费久久久久久无码 | 久久国产精品_国产精品 | 欧美日本日韩 | 日本饥渴人妻欲求不满 | 少妇性荡欲午夜性开放视频剧场 | 国产无套粉嫩白浆在线 | 人人妻人人澡人人爽欧美一区 | 久久99精品国产麻豆蜜芽 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | aⅴ亚洲 日韩 色 图网站 播放 | 99re在线播放 | 国产精品亚洲专区无码不卡 | 久久国产精品萌白酱免费 | 蜜桃视频插满18在线观看 | 午夜精品久久久久久久 | 无码国产色欲xxxxx视频 | 亚洲男女内射在线播放 | 日韩精品乱码av一区二区 | 日韩亚洲欧美精品综合 | 精品国产av色一区二区深夜久久 | 国产成人无码午夜视频在线观看 | а√资源新版在线天堂 | 疯狂三人交性欧美 | 最新国产乱人伦偷精品免费网站 | 麻豆成人精品国产免费 | 日本精品少妇一区二区三区 | 欧美精品无码一区二区三区 | 大地资源网第二页免费观看 | av无码电影一区二区三区 | 俺去俺来也www色官网 | 欧美成人免费全部网站 | 一本久道久久综合婷婷五月 | 国产明星裸体无码xxxx视频 | 久久精品人妻少妇一区二区三区 | 成人欧美一区二区三区 | 纯爱无遮挡h肉动漫在线播放 | 精品国产精品久久一区免费式 | 色窝窝无码一区二区三区色欲 | 久久国产精品精品国产色婷婷 | 国产精品第一区揄拍无码 | 精品成人av一区二区三区 | 久久久久久av无码免费看大片 | 国产午夜无码视频在线观看 | 精品人妻人人做人人爽夜夜爽 | 一二三四社区在线中文视频 | 久久熟妇人妻午夜寂寞影院 | 99久久久国产精品无码免费 | 在线欧美精品一区二区三区 | 亚洲精品一区二区三区在线 | 久久亚洲中文字幕精品一区 | 日本一本二本三区免费 | 日韩欧美群交p片內射中文 | 成人精品一区二区三区中文字幕 | 夜精品a片一区二区三区无码白浆 | 久久久久久九九精品久 | 男女超爽视频免费播放 | 免费中文字幕日韩欧美 | 亚洲爆乳精品无码一区二区三区 | 亚洲小说春色综合另类 | 男女超爽视频免费播放 | 欧美大屁股xxxxhd黑色 | 人人妻人人澡人人爽欧美一区九九 | 亚洲成av人影院在线观看 | 99久久精品国产一区二区蜜芽 | 国产av一区二区精品久久凹凸 | 久久精品人人做人人综合 | 日本精品少妇一区二区三区 | 欧洲极品少妇 | 日韩人妻少妇一区二区三区 | 欧美 亚洲 国产 另类 | a在线观看免费网站大全 | 白嫩日本少妇做爰 | 日日噜噜噜噜夜夜爽亚洲精品 | 国产精品久久久久久久9999 | 久久综合狠狠综合久久综合88 | 一本久久a久久精品vr综合 | 成人免费视频一区二区 | 日本精品少妇一区二区三区 | 午夜不卡av免费 一本久久a久久精品vr综合 | 久久国产精品_国产精品 | 中文字幕乱码人妻无码久久 | 精品无码国产自产拍在线观看蜜 | 亚洲成av人影院在线观看 | 国产综合色产在线精品 | 红桃av一区二区三区在线无码av | 台湾无码一区二区 | 亚洲一区二区三区含羞草 | 国产在线aaa片一区二区99 | 亚洲日韩乱码中文无码蜜桃臀网站 | 久久综合给久久狠狠97色 | 日本乱偷人妻中文字幕 | 国产精品资源一区二区 | 久久精品国产一区二区三区肥胖 | 国产精品无码mv在线观看 | 国产av久久久久精东av | 成人一区二区免费视频 | 免费国产成人高清在线观看网站 | 亚洲国产精华液网站w | 日韩人妻无码一区二区三区久久99 | 成年女人永久免费看片 | 水蜜桃av无码 | 最近的中文字幕在线看视频 | 免费观看又污又黄的网站 | 亚洲成a人一区二区三区 | 久久久婷婷五月亚洲97号色 | 婷婷丁香五月天综合东京热 | 熟妇人妻激情偷爽文 | 欧美熟妇另类久久久久久不卡 | 欧美丰满熟妇xxxx性ppx人交 | 国产精品99久久精品爆乳 | 高清国产亚洲精品自在久久 | 日日天日日夜日日摸 | 一个人看的视频www在线 | www国产亚洲精品久久网站 | 国产精品亚洲一区二区三区喷水 | 又色又爽又黄的美女裸体网站 | 图片区 小说区 区 亚洲五月 | 风流少妇按摩来高潮 | 人人澡人人透人人爽 | 天天综合网天天综合色 | 国产成人无码a区在线观看视频app | 欧美日本免费一区二区三区 | 又湿又紧又大又爽a视频国产 | 人妻少妇精品无码专区二区 | 欧洲美熟女乱又伦 | 亚洲精品成人福利网站 | 国产香蕉尹人综合在线观看 | 欧美精品免费观看二区 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 欧美怡红院免费全部视频 | 精品国产精品久久一区免费式 | 欧美丰满熟妇xxxx | 18黄暴禁片在线观看 | 草草网站影院白丝内射 | 成人影院yy111111在线观看 | 欧美xxxxx精品 | 亚洲 日韩 欧美 成人 在线观看 | 欧美日韩一区二区综合 | 欧美一区二区三区 | 男女爱爱好爽视频免费看 | 国产又爽又猛又粗的视频a片 | 伊人久久大香线蕉午夜 | 欧美色就是色 | 蜜桃av抽搐高潮一区二区 | 久久综合九色综合97网 | 在线看片无码永久免费视频 | 亚洲欧美精品伊人久久 | 国内综合精品午夜久久资源 | 久久国产精品精品国产色婷婷 | 18无码粉嫩小泬无套在线观看 | 欧美日韩人成综合在线播放 | 久久精品国产精品国产精品污 | 久精品国产欧美亚洲色aⅴ大片 | 丰满人妻一区二区三区免费视频 | 无码精品人妻一区二区三区av | 强伦人妻一区二区三区视频18 | 中文字幕无码日韩专区 | 无码国产乱人伦偷精品视频 | 九月婷婷人人澡人人添人人爽 | 少妇太爽了在线观看 | 精品日本一区二区三区在线观看 | 无码人妻少妇伦在线电影 | 无码精品国产va在线观看dvd | 国产亚av手机在线观看 | 国产av剧情md精品麻豆 | 麻豆md0077饥渴少妇 | 国产乱子伦视频在线播放 | 综合激情五月综合激情五月激情1 | 久久综合狠狠综合久久综合88 | 久久综合九色综合97网 | av在线亚洲欧洲日产一区二区 | 日本在线高清不卡免费播放 | 久热国产vs视频在线观看 | 久久久精品欧美一区二区免费 | 鲁大师影院在线观看 | 牛和人交xxxx欧美 | 女人高潮内射99精品 | a国产一区二区免费入口 | 久激情内射婷内射蜜桃人妖 | 国产无遮挡又黄又爽又色 | 国产免费久久精品国产传媒 | 久久久久人妻一区精品色欧美 | 亚洲人亚洲人成电影网站色 | 色婷婷av一区二区三区之红樱桃 | 日本xxxx色视频在线观看免费 | 国产精品人人爽人人做我的可爱 | 男人的天堂2018无码 | 色综合视频一区二区三区 | 国产熟女一区二区三区四区五区 | 亚洲国产成人av在线观看 | 中文字幕无码热在线视频 | 亚洲国产欧美国产综合一区 | 欧美乱妇无乱码大黄a片 | 好屌草这里只有精品 | 大屁股大乳丰满人妻 | 中文字幕无码乱人伦 | 亚洲熟妇色xxxxx欧美老妇y | 亚洲欧美中文字幕5发布 | 国产成人精品久久亚洲高清不卡 | 日韩精品乱码av一区二区 | 老司机亚洲精品影院无码 | 中文字幕色婷婷在线视频 | 永久黄网站色视频免费直播 | 日日摸日日碰夜夜爽av | 国产成人一区二区三区别 | 伊人久久大香线蕉av一区二区 | 蜜臀aⅴ国产精品久久久国产老师 | 又湿又紧又大又爽a视频国产 | 国内丰满熟女出轨videos | 亚洲一区二区三区在线观看网站 | 精品无码av一区二区三区 | 中国大陆精品视频xxxx | 国产精品亚洲а∨无码播放麻豆 | 日韩精品a片一区二区三区妖精 | 红桃av一区二区三区在线无码av | 人妻有码中文字幕在线 | 性色欲情网站iwww九文堂 | 欧美性生交xxxxx久久久 | 中文亚洲成a人片在线观看 | 欧美变态另类xxxx | 国产精品欧美成人 | 国产午夜手机精彩视频 | 香港三级日本三级妇三级 | 久久久久久久久蜜桃 | 国产莉萝无码av在线播放 | 少妇被粗大的猛进出69影院 | 亚洲乱码国产乱码精品精 | 日韩欧美成人免费观看 | 久久精品成人欧美大片 | 一本久道久久综合婷婷五月 | 图片小说视频一区二区 | 久久99久久99精品中文字幕 | 露脸叫床粗话东北少妇 | 欧美xxxx黑人又粗又长 | 中文字幕无线码 | 国产精品视频免费播放 | 国产在线无码精品电影网 | 国产后入清纯学生妹 | 亚洲中文字幕在线无码一区二区 | 无码人妻av免费一区二区三区 | 内射爽无广熟女亚洲 | 欧美精品一区二区精品久久 | 十八禁真人啪啪免费网站 | 国产无套内射久久久国产 | 亚洲国产精品久久久久久 | 亚洲а∨天堂久久精品2021 | 精品人妻人人做人人爽夜夜爽 | 国产精品沙发午睡系列 | 午夜精品一区二区三区的区别 | 免费观看激色视频网站 | 国产另类ts人妖一区二区 | 精品国产aⅴ无码一区二区 | 国产精品久久久久久亚洲影视内衣 | 色情久久久av熟女人妻网站 | 亚洲成色在线综合网站 | 大地资源中文第3页 | 亚洲高清偷拍一区二区三区 | 精品无码一区二区三区的天堂 | 国产成人精品无码播放 | 国产另类ts人妖一区二区 | 欧美自拍另类欧美综合图片区 | 在线 国产 欧美 亚洲 天堂 | 久久人人97超碰a片精品 | 国产一区二区三区精品视频 | 人妻无码久久精品人妻 | 国产人成高清在线视频99最全资源 | 亚洲爆乳大丰满无码专区 | 麻豆国产97在线 | 欧洲 | 在线观看免费人成视频 | 女人高潮内射99精品 | 国产精品a成v人在线播放 | 四虎影视成人永久免费观看视频 | 久久久久se色偷偷亚洲精品av | 无码精品人妻一区二区三区av | 久久亚洲中文字幕无码 | 日韩精品乱码av一区二区 | 亚洲性无码av中文字幕 | 奇米影视888欧美在线观看 | 牲欲强的熟妇农村老妇女 | 女人被爽到呻吟gif动态图视看 | 图片小说视频一区二区 | 三上悠亚人妻中文字幕在线 | 亚洲第一无码av无码专区 | 欧美xxxxx精品 | 牛和人交xxxx欧美 | 丰满妇女强制高潮18xxxx | 日韩精品无码一区二区中文字幕 | 欧美性色19p | 国产精品无码永久免费888 | 成人免费视频视频在线观看 免费 | 欧美第一黄网免费网站 | 国产成人亚洲综合无码 | 99久久人妻精品免费二区 | 色婷婷av一区二区三区之红樱桃 | 欧美丰满老熟妇xxxxx性 | 国产国产精品人在线视 | 在线天堂新版最新版在线8 | 女人被男人爽到呻吟的视频 | 久久国语露脸国产精品电影 | 日本护士毛茸茸高潮 | 日韩亚洲欧美中文高清在线 | 亚洲人成网站色7799 | 少妇无码av无码专区在线观看 | 亚洲欧美日韩成人高清在线一区 | 久久精品人妻少妇一区二区三区 | 欧美黑人性暴力猛交喷水 | 亚洲中文字幕无码中字 | ass日本丰满熟妇pics | 亚洲中文字幕成人无码 | 99久久人妻精品免费二区 | 国产疯狂伦交大片 | 精品乱子伦一区二区三区 | 无码人妻少妇伦在线电影 | 久久精品国产大片免费观看 | 全黄性性激高免费视频 | 给我免费的视频在线观看 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 在线观看免费人成视频 | 国产人妻精品一区二区三区 | 狠狠色噜噜狠狠狠7777奇米 | 成人精品视频一区二区 | 亚洲男人av天堂午夜在 | 麻豆国产丝袜白领秘书在线观看 | 亚洲一区二区观看播放 | 国产成人一区二区三区在线观看 | 亚洲色欲色欲天天天www | v一区无码内射国产 | 欧美熟妇另类久久久久久不卡 | 桃花色综合影院 | 狠狠噜狠狠狠狠丁香五月 | 精品一区二区三区无码免费视频 | 亚洲国产精品一区二区第一页 | 国产97色在线 | 免 | 精品国产乱码久久久久乱码 | 精品一二三区久久aaa片 | 色欲综合久久中文字幕网 | 大地资源中文第3页 | 国产免费无码一区二区视频 | 给我免费的视频在线观看 | 少妇无码av无码专区在线观看 | 中文无码精品a∨在线观看不卡 | 国内老熟妇对白xxxxhd | 久久精品人人做人人综合 | 波多野结衣av在线观看 | 天天做天天爱天天爽综合网 | 无码av最新清无码专区吞精 | 亚洲自偷精品视频自拍 | 亚洲精品国产精品乱码不卡 | 国产精品久久久久无码av色戒 | 亚洲日韩乱码中文无码蜜桃臀网站 | 黑人大群体交免费视频 | 老太婆性杂交欧美肥老太 | 国产精品嫩草久久久久 | 青草视频在线播放 | 国产激情艳情在线看视频 | 一本久久伊人热热精品中文字幕 | 高潮毛片无遮挡高清免费视频 | 日本一区二区三区免费高清 | 国产成人精品一区二区在线小狼 | 亚洲熟妇色xxxxx欧美老妇y | 天堂а√在线中文在线 | 无遮挡国产高潮视频免费观看 | 久久精品女人天堂av免费观看 | 国产深夜福利视频在线 | 精品久久综合1区2区3区激情 | 乱码av麻豆丝袜熟女系列 | 国产精品高潮呻吟av久久 | 欧美zoozzooz性欧美 | 乱人伦人妻中文字幕无码久久网 | 精品人妻人人做人人爽夜夜爽 | 99久久精品无码一区二区毛片 | 欧美老妇交乱视频在线观看 | 国产成人精品优优av | a片在线免费观看 | 无码帝国www无码专区色综合 | 无码国产色欲xxxxx视频 | 扒开双腿吃奶呻吟做受视频 | 久久国产精品精品国产色婷婷 | 欧美性黑人极品hd | 欧美喷潮久久久xxxxx | 日韩亚洲欧美精品综合 | 精品国产麻豆免费人成网站 | 少妇被粗大的猛进出69影院 | 欧美真人作爱免费视频 | 欧美日本日韩 | 免费播放一区二区三区 | 午夜肉伦伦影院 | 无码av岛国片在线播放 | 大肉大捧一进一出视频出来呀 | 精品日本一区二区三区在线观看 | aⅴ在线视频男人的天堂 | 5858s亚洲色大成网站www | 色一情一乱一伦一区二区三欧美 | 亚洲性无码av中文字幕 | 初尝人妻少妇中文字幕 | 麻豆人妻少妇精品无码专区 | 精品无码国产一区二区三区av | 在线欧美精品一区二区三区 | 性生交大片免费看l | 精品国精品国产自在久国产87 | 久久久久成人精品免费播放动漫 | 亚洲熟妇自偷自拍另类 | 精品久久久久香蕉网 | 欧美成人高清在线播放 | 丰满人妻被黑人猛烈进入 | 风流少妇按摩来高潮 | 永久免费精品精品永久-夜色 | 亚洲小说图区综合在线 | 老子影院午夜伦不卡 | 国精品人妻无码一区二区三区蜜柚 | 亚洲国产高清在线观看视频 | 男女作爱免费网站 | 人人妻人人澡人人爽欧美精品 | 国产精品丝袜黑色高跟鞋 | 天堂亚洲2017在线观看 | 97资源共享在线视频 | 成熟人妻av无码专区 | 亚洲中文字幕无码中字 | 免费中文字幕日韩欧美 | 亚洲aⅴ无码成人网站国产app | 偷窥日本少妇撒尿chinese | 久久精品女人天堂av免费观看 | 国产精品美女久久久网av | 无码av岛国片在线播放 | 内射老妇bbwx0c0ck | 国产97色在线 | 免 | 人妻体内射精一区二区三四 | 欧美 日韩 人妻 高清 中文 | 国产成人一区二区三区在线观看 | 性生交片免费无码看人 | 伊在人天堂亚洲香蕉精品区 | 日本一卡2卡3卡四卡精品网站 | 国产精品久久久久影院嫩草 | 狂野欧美性猛xxxx乱大交 | 中文无码伦av中文字幕 | 99久久婷婷国产综合精品青草免费 | 日本饥渴人妻欲求不满 | 色综合久久久无码网中文 | 日本高清一区免费中文视频 | 影音先锋中文字幕无码 | 男女下面进入的视频免费午夜 | 男人扒开女人内裤强吻桶进去 | 色综合久久88色综合天天 | 成 人 网 站国产免费观看 | 国产精品久久久午夜夜伦鲁鲁 | 亚洲理论电影在线观看 | 国精产品一区二区三区 | 天天拍夜夜添久久精品大 | 麻豆av传媒蜜桃天美传媒 | 亚洲人成无码网www | 国产精品久久久午夜夜伦鲁鲁 | 国产乱人伦偷精品视频 | 国内少妇偷人精品视频免费 | а√天堂www在线天堂小说 | 中文字幕av日韩精品一区二区 | 欧美日本日韩 | 国产福利视频一区二区 | 久久久久99精品成人片 | 精品国产av色一区二区深夜久久 | 国产九九九九九九九a片 | 人人爽人人澡人人人妻 | av无码电影一区二区三区 | 亚洲成av人片天堂网无码】 | 最近的中文字幕在线看视频 | 精品人妻中文字幕有码在线 | 亚洲人成影院在线观看 | 成 人 网 站国产免费观看 | 久久精品女人天堂av免费观看 | 18禁黄网站男男禁片免费观看 | 久久精品国产大片免费观看 | 台湾无码一区二区 | 人人妻人人澡人人爽人人精品浪潮 | 天堂亚洲2017在线观看 | 亚洲国产欧美在线成人 | 97精品人妻一区二区三区香蕉 | 天天综合网天天综合色 | 2020久久香蕉国产线看观看 | 亚洲小说春色综合另类 | 国产成人一区二区三区在线观看 | 国产 精品 自在自线 | 无码人妻精品一区二区三区不卡 | 国产免费久久久久久无码 | 精品国产精品久久一区免费式 | 人妻人人添人妻人人爱 | 国产午夜无码精品免费看 | 久久 国产 尿 小便 嘘嘘 | 初尝人妻少妇中文字幕 | 97夜夜澡人人双人人人喊 | 久精品国产欧美亚洲色aⅴ大片 | 无码国内精品人妻少妇 | 国产特级毛片aaaaaa高潮流水 | 性欧美牲交在线视频 | 国产超碰人人爽人人做人人添 | 伊在人天堂亚洲香蕉精品区 | 国产精品理论片在线观看 | 黑人巨大精品欧美一区二区 | 麻豆md0077饥渴少妇 | 4hu四虎永久在线观看 | 久久综合网欧美色妞网 | 精品国偷自产在线 | 国产亚洲美女精品久久久2020 | 国产成人精品久久亚洲高清不卡 | 成 人 网 站国产免费观看 | 少妇一晚三次一区二区三区 | 中文字幕中文有码在线 | 亚洲区小说区激情区图片区 | 牛和人交xxxx欧美 | 99精品视频在线观看免费 | 亚洲va中文字幕无码久久不卡 | 清纯唯美经典一区二区 | 亚洲无人区一区二区三区 | 亚洲一区二区三区 | 国产真实乱对白精彩久久 | 国産精品久久久久久久 | 亚洲成熟女人毛毛耸耸多 | 无码毛片视频一区二区本码 | 丰满岳乱妇在线观看中字无码 | 国产精品久久福利网站 | 亚洲国产欧美国产综合一区 | 中文字幕乱码亚洲无线三区 | 国内精品九九久久久精品 | 久久97精品久久久久久久不卡 | 内射老妇bbwx0c0ck | 一二三四在线观看免费视频 | 亚洲国产欧美国产综合一区 | 一本久道高清无码视频 | 久久久久人妻一区精品色欧美 | 亚洲综合在线一区二区三区 | 日日橹狠狠爱欧美视频 | 性欧美熟妇videofreesex | 亚洲成av人综合在线观看 | 日本成熟视频免费视频 | 亚洲 日韩 欧美 成人 在线观看 | 88国产精品欧美一区二区三区 | 131美女爱做视频 | 亚洲综合无码一区二区三区 | 国产免费无码一区二区视频 | 国产精品鲁鲁鲁 | 国产成人综合色在线观看网站 | 国产精品久久久久无码av色戒 | 丰满人妻被黑人猛烈进入 | 国产精品丝袜黑色高跟鞋 | 一区二区传媒有限公司 | 亚洲精品国产精品乱码不卡 | 一个人免费观看的www视频 | 久久精品人妻少妇一区二区三区 | 人妻尝试又大又粗久久 | 精品无码一区二区三区的天堂 | 狠狠色欧美亚洲狠狠色www | 国产激情综合五月久久 | 亚洲熟妇色xxxxx亚洲 | 久久亚洲精品中文字幕无男同 | 波多野结衣高清一区二区三区 | 成人一在线视频日韩国产 | 国产成人精品无码播放 | 精品熟女少妇av免费观看 | 呦交小u女精品视频 | 天天躁夜夜躁狠狠是什么心态 | 亚洲爆乳精品无码一区二区三区 | 亚洲日本va午夜在线电影 | 女人被男人躁得好爽免费视频 | 欧美 日韩 人妻 高清 中文 | 亚洲中文无码av永久不收费 | 丰满人妻翻云覆雨呻吟视频 | 久久国产劲爆∧v内射 | 一二三四在线观看免费视频 | 伊人久久大香线蕉午夜 | aa片在线观看视频在线播放 | 思思久久99热只有频精品66 | 国产 精品 自在自线 | 国产精品久久久久无码av色戒 | 天天燥日日燥 | 日本又色又爽又黄的a片18禁 | 国产精品igao视频网 | 久久成人a毛片免费观看网站 | 成人免费视频在线观看 | 性欧美牲交xxxxx视频 | 国产乱人偷精品人妻a片 | 日韩 欧美 动漫 国产 制服 | 国产高潮视频在线观看 | 亚洲精品久久久久久久久久久 | 图片小说视频一区二区 | 最新国产乱人伦偷精品免费网站 | 国内丰满熟女出轨videos | 全球成人中文在线 | 国产色在线 | 国产 | 午夜精品久久久久久久 | 日韩欧美群交p片內射中文 | 国产三级久久久精品麻豆三级 | 国产乱子伦视频在线播放 | 2020最新国产自产精品 | 精品日本一区二区三区在线观看 | 日韩少妇内射免费播放 | 亚洲七七久久桃花影院 | 久久久精品成人免费观看 | 最新国产麻豆aⅴ精品无码 | 国产精品a成v人在线播放 | 亚洲a无码综合a国产av中文 | 欧美日本精品一区二区三区 | 亚洲色大成网站www | 桃花色综合影院 | 高清不卡一区二区三区 | 久久综合香蕉国产蜜臀av | 欧美丰满少妇xxxx性 | 综合激情五月综合激情五月激情1 | 欧美日韩综合一区二区三区 | 日本在线高清不卡免费播放 | 日本一区二区更新不卡 | 熟妇人妻无乱码中文字幕 | 中文字幕久久久久人妻 | 中文字幕av伊人av无码av | 精品国产国产综合精品 | 大乳丰满人妻中文字幕日本 | 中国大陆精品视频xxxx | 国产亚洲日韩欧美另类第八页 | 亚洲色在线无码国产精品不卡 | 四虎国产精品免费久久 | 国产99久久精品一区二区 | 成人免费无码大片a毛片 | 日韩精品无码免费一区二区三区 | 国产精品沙发午睡系列 | 国产97人人超碰caoprom | 精品夜夜澡人妻无码av蜜桃 | 国产亚洲精品久久久ai换 | 天堂亚洲免费视频 | 久久久中文久久久无码 | 性欧美牲交在线视频 | 激情内射亚州一区二区三区爱妻 | 国产真人无遮挡作爱免费视频 | 青青青手机频在线观看 | 在线视频网站www色 | 欧洲欧美人成视频在线 | 国産精品久久久久久久 | 综合激情五月综合激情五月激情1 | 精品一区二区三区波多野结衣 | 国产精品久久国产三级国 | 久久久国产精品无码免费专区 | 久久人人爽人人人人片 | 日欧一片内射va在线影院 | 精品国产青草久久久久福利 | 性欧美videos高清精品 | 天堂一区人妻无码 | 日韩精品成人一区二区三区 | 中文字幕乱码人妻二区三区 | 亚洲国产精品一区二区美利坚 | 国产黄在线观看免费观看不卡 | 又黄又爽又色的视频 | 久久精品中文闷骚内射 | 欧美高清在线精品一区 | 国产黄在线观看免费观看不卡 | 性色av无码免费一区二区三区 | 2020最新国产自产精品 | 日本一本二本三区免费 | 亚洲一区二区三区在线观看网站 | 成人性做爰aaa片免费看 | 国产免费无码一区二区视频 | 亚洲中文字幕在线无码一区二区 | 国产内射爽爽大片视频社区在线 | 荫蒂被男人添的好舒服爽免费视频 | 精品一二三区久久aaa片 | 无码人妻出轨黑人中文字幕 | 一本久久a久久精品亚洲 | 成人一在线视频日韩国产 | 国内精品人妻无码久久久影院 | 青春草在线视频免费观看 | 精品国产青草久久久久福利 | 99久久精品午夜一区二区 | 国产精品鲁鲁鲁 | 国内少妇偷人精品视频 | 国产亚洲精品久久久ai换 | 国产明星裸体无码xxxx视频 | 色综合久久中文娱乐网 | 亚洲爆乳大丰满无码专区 | 好屌草这里只有精品 | 成 人 网 站国产免费观看 | 人人爽人人澡人人高潮 | 综合网日日天干夜夜久久 | 女人被男人躁得好爽免费视频 | 欧美精品国产综合久久 | 日日麻批免费40分钟无码 | 日本丰满熟妇videos | 亚洲精品一区二区三区大桥未久 | a片免费视频在线观看 | 国内丰满熟女出轨videos | 婷婷综合久久中文字幕蜜桃三电影 | 亚洲性无码av中文字幕 | av在线亚洲欧洲日产一区二区 | 免费观看黄网站 | 欧美国产日产一区二区 | 久久久久av无码免费网 | 野狼第一精品社区 | 麻豆人妻少妇精品无码专区 | 性欧美熟妇videofreesex | 欧美人妻一区二区三区 | 麻豆av传媒蜜桃天美传媒 | 小sao货水好多真紧h无码视频 | 亚洲欧美日韩成人高清在线一区 | 亚洲成在人网站无码天堂 | 色欲av亚洲一区无码少妇 | 国产精品自产拍在线观看 | 欧美野外疯狂做受xxxx高潮 | 久久亚洲中文字幕无码 | 亚洲国产精品无码久久久久高潮 | 性色av无码免费一区二区三区 | 亚洲日韩乱码中文无码蜜桃臀网站 | 久久国产精品二国产精品 | 性生交片免费无码看人 | 国产成人无码av片在线观看不卡 | 少妇无码av无码专区在线观看 | 精品国产乱码久久久久乱码 | 欧美黑人巨大xxxxx | 亚洲精品中文字幕久久久久 | 沈阳熟女露脸对白视频 | 国产av一区二区精品久久凹凸 | 成人aaa片一区国产精品 | 日日噜噜噜噜夜夜爽亚洲精品 | 成人动漫在线观看 | 清纯唯美经典一区二区 | 国产亚洲视频中文字幕97精品 | 欧美 亚洲 国产 另类 | 性欧美videos高清精品 | 日本爽爽爽爽爽爽在线观看免 | 97久久国产亚洲精品超碰热 | 国产亚av手机在线观看 | 成人一区二区免费视频 | 中文字幕亚洲情99在线 | 欧美亚洲国产一区二区三区 | 全黄性性激高免费视频 | 伊在人天堂亚洲香蕉精品区 | a片在线免费观看 | 亚洲成在人网站无码天堂 | 精品国产乱码久久久久乱码 | www一区二区www免费 | 成人欧美一区二区三区黑人免费 | 丰满少妇弄高潮了www | 久久zyz资源站无码中文动漫 | 久久精品人人做人人综合试看 | 99久久精品无码一区二区毛片 | 亚洲国产成人av在线观看 | 午夜男女很黄的视频 | 人人妻人人澡人人爽欧美一区 | 国产在线精品一区二区三区直播 | 1000部啪啪未满十八勿入下载 | 亚拍精品一区二区三区探花 | 99re在线播放 | 99久久精品午夜一区二区 | 国产免费久久久久久无码 | 亚洲小说图区综合在线 | 婷婷丁香六月激情综合啪 | 国产精品免费大片 | 久久久久99精品国产片 | 中文字幕无码免费久久99 | 国产成人无码一二三区视频 | 久久国产自偷自偷免费一区调 | 性欧美熟妇videofreesex | 日韩av无码中文无码电影 | 天天拍夜夜添久久精品 | ass日本丰满熟妇pics | 沈阳熟女露脸对白视频 | 国产综合色产在线精品 | 精品国产精品久久一区免费式 | 色欲综合久久中文字幕网 | 国产乱人伦av在线无码 | 精品人人妻人人澡人人爽人人 | 成熟女人特级毛片www免费 | 国产亚av手机在线观看 | 国产人成高清在线视频99最全资源 | 亚洲精品午夜国产va久久成人 | 午夜精品一区二区三区的区别 | 中文字幕无码热在线视频 | 男人扒开女人内裤强吻桶进去 | 国内揄拍国内精品少妇国语 | 国产精品嫩草久久久久 | 日本精品人妻无码77777 天堂一区人妻无码 | 亚洲 a v无 码免 费 成 人 a v | 中文字幕无码视频专区 | 欧美高清在线精品一区 | 一本色道婷婷久久欧美 | 亚洲欧美国产精品久久 | 激情五月综合色婷婷一区二区 | 少妇无套内谢久久久久 | 久久视频在线观看精品 | 亚洲の无码国产の无码影院 | 久9re热视频这里只有精品 | 性做久久久久久久久 | 日韩人妻无码中文字幕视频 | 麻豆国产丝袜白领秘书在线观看 | 欧美激情一区二区三区成人 | 福利一区二区三区视频在线观看 | 国内精品一区二区三区不卡 | 青青青手机频在线观看 | 55夜色66夜色国产精品视频 | 少妇太爽了在线观看 | 国产av一区二区精品久久凹凸 | 性生交片免费无码看人 | 一本色道久久综合亚洲精品不卡 | 老头边吃奶边弄进去呻吟 | 99国产精品白浆在线观看免费 | 性欧美疯狂xxxxbbbb | 窝窝午夜理论片影院 | 波多野42部无码喷潮在线 | 亚洲精品国产精品乱码视色 | 久久综合久久自在自线精品自 | 丁香啪啪综合成人亚洲 | 色婷婷久久一区二区三区麻豆 | 国产精品美女久久久久av爽李琼 | 国产农村妇女高潮大叫 | 久久精品一区二区三区四区 | 国产av一区二区三区最新精品 | 国产后入清纯学生妹 | 亚欧洲精品在线视频免费观看 | 久久精品中文闷骚内射 | 亚洲а∨天堂久久精品2021 | 在线播放亚洲第一字幕 | 乱码午夜-极国产极内射 | 全黄性性激高免费视频 | 丝袜人妻一区二区三区 | 国产精品美女久久久久av爽李琼 | 丝袜 中出 制服 人妻 美腿 | 亚洲区小说区激情区图片区 | 久久精品丝袜高跟鞋 | 天天做天天爱天天爽综合网 | 久久精品国产99精品亚洲 | 亚洲 日韩 欧美 成人 在线观看 | 99久久精品日本一区二区免费 | 成熟女人特级毛片www免费 | 亚洲成色在线综合网站 | 亚洲国产高清在线观看视频 | 日日碰狠狠丁香久燥 | 亚洲一区二区三区在线观看网站 | а天堂中文在线官网 | 亚洲综合无码一区二区三区 | 亚洲午夜福利在线观看 | 欧美野外疯狂做受xxxx高潮 | 中文字幕中文有码在线 | 色婷婷欧美在线播放内射 | 又色又爽又黄的美女裸体网站 | 国产精品久久国产精品99 | 国产一精品一av一免费 | 久久99精品国产.久久久久 | 国内精品久久毛片一区二区 | 国产精品人人妻人人爽 | 亚洲毛片av日韩av无码 | 亚洲 a v无 码免 费 成 人 a v | 天下第一社区视频www日本 | 国产做国产爱免费视频 | 又粗又大又硬又长又爽 | 中文字幕人妻无码一夲道 | 国产香蕉尹人视频在线 | 久久99精品久久久久久动态图 | 黑人巨大精品欧美一区二区 | 自拍偷自拍亚洲精品10p | 亚洲人成人无码网www国产 | 亚洲国产精品一区二区美利坚 | 成年美女黄网站色大免费全看 | 免费人成在线观看网站 | 丰满少妇熟乱xxxxx视频 | 久久亚洲精品成人无码 | 国产另类ts人妖一区二区 | 熟妇人妻中文av无码 | 人妻天天爽夜夜爽一区二区 | 日产精品高潮呻吟av久久 | 精品久久久久久人妻无码中文字幕 | 日本乱偷人妻中文字幕 | 亚洲精品国偷拍自产在线观看蜜桃 | 国产色精品久久人妻 | 精品久久久无码中文字幕 | 久久99精品国产麻豆 | 日韩 欧美 动漫 国产 制服 | 国产在线一区二区三区四区五区 | 一二三四社区在线中文视频 | 精品久久综合1区2区3区激情 | 国产乱人伦偷精品视频 | 成人欧美一区二区三区 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 欧美激情内射喷水高潮 | 亚洲最大成人网站 | 午夜精品一区二区三区的区别 | 欧美性猛交xxxx富婆 | 女人被爽到呻吟gif动态图视看 | 亚洲中文字幕在线无码一区二区 | 3d动漫精品啪啪一区二区中 | 国产真实夫妇视频 | 欧美阿v高清资源不卡在线播放 | 国产精品亚洲专区无码不卡 | 日本一区二区三区免费高清 | 久久综合激激的五月天 | 精品久久久无码中文字幕 | 欧洲美熟女乱又伦 | 成人免费视频在线观看 | 亚洲 激情 小说 另类 欧美 | 天天拍夜夜添久久精品 | 无码av免费一区二区三区试看 | 在线观看国产一区二区三区 | 少妇性荡欲午夜性开放视频剧场 | 天天燥日日燥 | 日本又色又爽又黄的a片18禁 | 亚洲中文字幕av在天堂 | 巨爆乳无码视频在线观看 | 青青草原综合久久大伊人精品 | 丰满少妇人妻久久久久久 | 日韩人妻系列无码专区 | www成人国产高清内射 | 老熟女乱子伦 | a片免费视频在线观看 | 亚洲 a v无 码免 费 成 人 a v | 国产国语老龄妇女a片 | 亚洲熟妇色xxxxx欧美老妇 | 亚洲色偷偷男人的天堂 | 伊人久久大香线蕉av一区二区 | 国语精品一区二区三区 | 亚洲综合伊人久久大杳蕉 | 亚洲中文字幕久久无码 | 国产精品内射视频免费 | 成人欧美一区二区三区黑人免费 | 性欧美牲交xxxxx视频 | 无码av中文字幕免费放 | 纯爱无遮挡h肉动漫在线播放 | 麻豆果冻传媒2021精品传媒一区下载 | 51国偷自产一区二区三区 | 99久久婷婷国产综合精品青草免费 | 国产亚洲精品久久久ai换 | 国色天香社区在线视频 | 亚洲а∨天堂久久精品2021 | aa片在线观看视频在线播放 | 精品乱码久久久久久久 | 无码一区二区三区在线 | 18黄暴禁片在线观看 | 亚洲熟妇色xxxxx亚洲 | 性欧美牲交在线视频 | 红桃av一区二区三区在线无码av | 欧美日韩在线亚洲综合国产人 | 久久精品国产一区二区三区肥胖 | 国产av无码专区亚洲a∨毛片 | 亚洲综合久久一区二区 | 精品国精品国产自在久国产87 | 国产av久久久久精东av | 波多野结衣乳巨码无在线观看 | 天天拍夜夜添久久精品 | 久久久精品人妻久久影视 | 久久亚洲中文字幕无码 | a片免费视频在线观看 | 国产激情无码一区二区app | 色五月丁香五月综合五月 | 丝袜足控一区二区三区 | 色诱久久久久综合网ywww | 欧美国产日产一区二区 | 伊人色综合久久天天小片 | 国模大胆一区二区三区 | 日产精品99久久久久久 | 精品成人av一区二区三区 | 亚洲精品成人av在线 | 男女爱爱好爽视频免费看 | 久久综合九色综合欧美狠狠 | 狠狠色噜噜狠狠狠7777奇米 | 精品国偷自产在线视频 | 成人欧美一区二区三区黑人免费 | 男女猛烈xx00免费视频试看 | av无码久久久久不卡免费网站 | 国产xxx69麻豆国语对白 | 久久久精品欧美一区二区免费 | 无码人妻精品一区二区三区下载 | 成人影院yy111111在线观看 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 少妇厨房愉情理9仑片视频 | 成在人线av无码免费 | 性欧美牲交在线视频 | 久久综合色之久久综合 | 欧美熟妇另类久久久久久不卡 | 欧美熟妇另类久久久久久多毛 | 欧美 日韩 人妻 高清 中文 | 久久久久人妻一区精品色欧美 | 狂野欧美激情性xxxx | 国产乡下妇女做爰 | 国产成人av免费观看 | 亚洲一区二区三区播放 | av人摸人人人澡人人超碰下载 | 国产亚洲精品久久久闺蜜 | 成人av无码一区二区三区 | 成人动漫在线观看 | 国内丰满熟女出轨videos | 无码一区二区三区在线观看 | 久久亚洲a片com人成 | 日日碰狠狠躁久久躁蜜桃 | 性生交大片免费看女人按摩摩 | 色欲久久久天天天综合网精品 | 人人妻人人澡人人爽精品欧美 | 无码午夜成人1000部免费视频 | 女人被男人躁得好爽免费视频 | 国产女主播喷水视频在线观看 | 国内精品久久毛片一区二区 | 久久国产精品二国产精品 | 国产人成高清在线视频99最全资源 | 亚洲中文字幕久久无码 | 97人妻精品一区二区三区 | 丝袜 中出 制服 人妻 美腿 | 久久www免费人成人片 | 午夜时刻免费入口 | 免费无码的av片在线观看 | 国产无遮挡吃胸膜奶免费看 | 亚洲精品久久久久中文第一幕 | 亚洲aⅴ无码成人网站国产app | 无码精品国产va在线观看dvd | 欧美日韩色另类综合 | 人人妻人人澡人人爽人人精品 | 久久亚洲精品成人无码 | 蜜臀aⅴ国产精品久久久国产老师 | 久久国产精品偷任你爽任你 | 亚洲精品国产精品乱码不卡 | 亚洲欧美中文字幕5发布 | 欧美真人作爱免费视频 | 色窝窝无码一区二区三区色欲 | 97人妻精品一区二区三区 | 帮老师解开蕾丝奶罩吸乳网站 | 精品一区二区不卡无码av | 国产欧美熟妇另类久久久 | 最近中文2019字幕第二页 | 亚洲综合伊人久久大杳蕉 | 亚洲の无码国产の无码影院 | 大屁股大乳丰满人妻 | 亚洲娇小与黑人巨大交 | 亚洲人成人无码网www国产 | 国产一区二区三区影院 | 欧美喷潮久久久xxxxx | 色综合视频一区二区三区 | 大地资源中文第3页 | 97夜夜澡人人爽人人喊中国片 | 给我免费的视频在线观看 | 激情综合激情五月俺也去 | 精品久久久久久人妻无码中文字幕 | 女人被男人爽到呻吟的视频 | 久久久中文久久久无码 | 久久精品国产精品国产精品污 | 国产又粗又硬又大爽黄老大爷视 | 综合激情五月综合激情五月激情1 | 纯爱无遮挡h肉动漫在线播放 | 亚洲色成人中文字幕网站 | 欧美丰满老熟妇xxxxx性 | 狠狠色欧美亚洲狠狠色www | 国产激情艳情在线看视频 | 波多野结衣 黑人 | 欧美人妻一区二区三区 | 国产精品va在线播放 | 久久国产精品二国产精品 | 伊人久久大香线蕉亚洲 | 日韩人妻无码一区二区三区久久99 | 一本久久伊人热热精品中文字幕 | 老子影院午夜精品无码 | 久久久中文久久久无码 | 亚洲爆乳无码专区 | 全球成人中文在线 | 日本一区二区三区免费高清 | 中文字幕无码日韩专区 | 国产精品亚洲lv粉色 | 久久午夜无码鲁丝片秋霞 | 日韩无码专区 | 日本免费一区二区三区最新 | 精品夜夜澡人妻无码av蜜桃 | 无码吃奶揉捏奶头高潮视频 | 国产婷婷色一区二区三区在线 | 国产亚洲人成a在线v网站 | 丰满少妇熟乱xxxxx视频 | 在线观看免费人成视频 | 大肉大捧一进一出好爽视频 | 国产黄在线观看免费观看不卡 | 日本饥渴人妻欲求不满 | 色 综合 欧美 亚洲 国产 | 成人性做爰aaa片免费看 | 欧美午夜特黄aaaaaa片 | 日韩无套无码精品 | 又湿又紧又大又爽a视频国产 | 亚洲成av人综合在线观看 | 爽爽影院免费观看 | 国产亚洲精品久久久久久国模美 | 免费观看黄网站 | 亚洲熟熟妇xxxx | 日韩精品乱码av一区二区 | 亚洲国产精品久久久天堂 | 精品久久综合1区2区3区激情 | 久久久精品456亚洲影院 | 久久精品国产精品国产精品污 | 国产欧美熟妇另类久久久 | 亚洲国产综合无码一区 | 精品欧美一区二区三区久久久 | 久久久久久a亚洲欧洲av冫 | 在线播放亚洲第一字幕 | 国产精品久久久午夜夜伦鲁鲁 | 日韩av无码中文无码电影 | 国产成人精品久久亚洲高清不卡 | 性做久久久久久久免费看 | 国产性生交xxxxx无码 | 水蜜桃av无码 | 婷婷色婷婷开心五月四房播播 | 国产亚洲精品精品国产亚洲综合 | 亚洲狠狠婷婷综合久久 | 国产sm调教视频在线观看 | 风流少妇按摩来高潮 | 在线看片无码永久免费视频 | 精品乱码久久久久久久 | 大屁股大乳丰满人妻 | 夜精品a片一区二区三区无码白浆 | 色婷婷综合激情综在线播放 | 久久婷婷五月综合色国产香蕉 | 精品人妻中文字幕有码在线 | 好男人www社区 | 18精品久久久无码午夜福利 | 欧美性生交活xxxxxdddd | 国产舌乚八伦偷品w中 | 国产无套粉嫩白浆在线 | 综合人妻久久一区二区精品 | 亚洲成a人片在线观看无码3d | 巨爆乳无码视频在线观看 | 国产片av国语在线观看 | 无码人妻出轨黑人中文字幕 | 老熟妇乱子伦牲交视频 | 国内精品久久毛片一区二区 | 波多野42部无码喷潮在线 | 国产农村妇女高潮大叫 | 中文无码伦av中文字幕 | v一区无码内射国产 | 国产成人无码a区在线观看视频app | 欧美日韩一区二区综合 | 国产色xx群视频射精 | 女人高潮内射99精品 | 无码吃奶揉捏奶头高潮视频 |