




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、.基于C#的接口基礎(chǔ)教程第一節(jié) 接口慨述接口(interface)用來定義一種程序的協(xié)定。實現(xiàn)接口的類或者結(jié)構(gòu)要與接口的定義嚴(yán)格一致。有了這個協(xié)定,就可以拋開編程語言的限制(理論上)。接口可以從多個基接口繼承,而類或結(jié)構(gòu)可以實現(xiàn)多個接口。接口可以包含方法、屬性、事件和索引器。接口本身不提供它所定義的成員的實現(xiàn)。接口只指定實現(xiàn)該接口的類或接口必須提供的成員。 接口好比一種模版,這種模版定義了對象必須實現(xiàn)的方法,其目的就是讓這些方法可以作為接口實例被引用。接口不能被實例化。類可以實現(xiàn)多個接口并且通過這些實現(xiàn)的接口被索引。接口變量只能索引實現(xiàn)該接口的類的實例。例子:interface IMyExam
2、ple string thisint 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"和"ILis
3、tBox"繼承。 interface IControl void Paint( ) ; interface ITextBox: IControl void SetText(string text) ; interface IListBox: IControl void SetItems(string items) ; interface IComboBox: ITextBox, IListBox 類和結(jié)構(gòu)可以多重實例化接口。就像在下例中,類"EditBox"繼承了類"Control",同時從"IDataBound&quo
4、t;和"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"
5、的身份在"EditBox"類中實現(xiàn)。說明:1、C#中的接口是獨立于類來定義的。這與 C+模型是對立的,在 C+中接口實際上就是抽象基類。2、接口和類都可以繼承多個接口。3、而類可以繼承一個基類,接口根本不能繼承類。這種模型避免了 C+的多繼承問題,C+中不同基類中的實現(xiàn)可能出現(xiàn)沖突。因此也不再需要諸如虛擬繼承和顯式作用域這類復(fù)雜機(jī)制。C#的簡化接口模型有助于加快應(yīng)用程序的開發(fā)。4、一個接口定義一個只有抽象成員的引用類型。C#中一個接口實際所做的,僅僅只存在著方法標(biāo)志,但根本就沒有執(zhí)行代碼。這就暗示了不能實例化一個接口,只能實例化一個派生自該接口的對象。5、接口可以定義方法、
6、屬性和索引。所以,對比一個類,接口的特殊性是:當(dāng)定義一個類時,可以派生自多重接口,而你只能可以從僅有的一個類派生。接口與組件接口描述了組件對外提供的服務(wù)。在組件和組件之間、組件和客戶之間都通過接口進(jìn)行交互。因此組件一旦發(fā)布,它只能通過預(yù)先定義的接口來提供合理的、一致的服務(wù)。這種接口定義之間的穩(wěn)定性使客戶應(yīng)用開發(fā)者能夠構(gòu)造出堅固的應(yīng)用。一個組件可以實現(xiàn)多個組件接口,而一個特定的組件接口也可以被多個組件來實現(xiàn)。組件接口必須是能夠自我描述的。這意味著組件接口應(yīng)該不依賴于具體的實現(xiàn),將實現(xiàn)和接口分離徹底消除了接口的使用者和接口的實現(xiàn)者之間的耦合關(guān)系,增強(qiáng)了信息的封裝程度。同時這也要求組件接口必須使用一
7、種與組件實現(xiàn)無關(guān)的語言。目前組件接口的描述標(biāo)準(zhǔn)是IDL語言。由于接口是組件之間的協(xié)議,因此組件的接口一旦被發(fā)布,組件生產(chǎn)者就應(yīng)該盡可能地保持接口不變,任何對接口語法或語義上的改變,都有可能造成現(xiàn)有組件與客戶之間的聯(lián)系遭到破壞。每個組件都是自主的,有其獨特的功能,只能通過接口與外界通信。當(dāng)一個組件需要提供新的服務(wù)時,可以通過增加新的接口來實現(xiàn)。不會影響原接口已存在的客戶。而新的客戶可以重新選擇新的接口來獲得服務(wù)。組件化程序設(shè)計組件化程序設(shè)計方法繼承并發(fā)展了面向?qū)ο蟮某绦蛟O(shè)計方法。它把對象技術(shù)應(yīng)用于系統(tǒng)設(shè)計,對面向?qū)ο蟮某绦蛟O(shè)計的實現(xiàn)過程作了進(jìn)一步的抽象。我們可以把組件化程序設(shè)計方法用作構(gòu)造系統(tǒng)的
8、體系結(jié)構(gòu)層次的方法,并且可以使用面向?qū)ο蟮姆椒ê芊奖愕貙崿F(xiàn)組件。組件化程序設(shè)計強(qiáng)調(diào)真正的軟件可重用性和高度的互操作性。它側(cè)重于組件的產(chǎn)生和裝配,這兩方面一起構(gòu)成了組件化程序設(shè)計的核心。組件的產(chǎn)生過程不僅僅是應(yīng)用系統(tǒng)的需求,組件市場本身也推動了組件的發(fā)展,促進(jìn)了軟件廠商的交流與合作。組件的裝配使得軟件產(chǎn)品可以采用類似于搭積木的方法快速地建立起來,不僅可以縮短軟件產(chǎn)品的開發(fā)周期,同時也提高了系統(tǒng)的穩(wěn)定性和可靠性。組件程序設(shè)計的方法有以下幾個方面的特點:1、編程語言和開發(fā)環(huán)境的獨立性;2、組件位置的透明性;3、組件的進(jìn)程透明性;4、可擴(kuò)充性;5、可重用性;6、具有強(qiáng)有力的基礎(chǔ)設(shè)施;7、系統(tǒng)一級的公共
9、服務(wù);C#語言由于其許多優(yōu)點,十分適用于組件編程。但這并不是說C#是一門組件編程語言,也不是說C#提供了組件編程的工具。我們已經(jīng)多次指出,組件應(yīng)該具有與編程語言無關(guān)的特性。請讀者記住這一點:組件模型是一種規(guī)范,不管采用何種程序語言設(shè)計組件,都必須遵守這一規(guī)范。比如組裝計算機(jī)的例子,只要各個廠商為我們提供的配件規(guī)格、接口符合統(tǒng)一的標(biāo)準(zhǔn),這些配件組合起來就能協(xié)同工作,組件編程也是一樣。我們只是說,利用C#語言進(jìn)行組件編程將會給我們帶來更大的方便。知道了什么是接口,接下來就是怎樣定義接口,請看下一節(jié)-定義接口。第二節(jié) 定義接口從技術(shù)上講,接口是一組包含了函數(shù)型方法的數(shù)據(jù)結(jié)構(gòu)。通過這組數(shù)據(jù)結(jié)構(gòu),客戶代
10、碼可以調(diào)用組件對象的功能。定義接口的一般形式為:attributes modifiers interface identifier :base-list interface-body; 說明:1、attributes(可選):附加的定義性信息。2、modifiers(可選): 允許使用的修飾符有 new 和四個訪問修飾符。分別是:new、public、protected、internal、 private。在一個接口定義中同一修飾符不允許出現(xiàn)多次,new 修飾符只能出現(xiàn)在嵌套接口中,表示覆蓋了繼承而來的同名成員。The public, protected, internal, and priv
11、ate 修飾符定義了對接口的訪問權(quán)限。3、指示器和事件。4、identifier:接口名稱。 5、base-list(可選):包含一個或多個顯式基接口的列表,接口間由逗號分隔。 6、interface-body:對接口成員的定義。7、接口可以是命名空間或類的成員,并且可以包含下列成員的簽名: 方法、屬性、索引器 。8、一個接口可從一個或多個基接口繼承。接口這個概念在C#和Java中非常相似。接口的關(guān)鍵詞是interface,一個接口可以擴(kuò)展一個或者多個其他接口。按照慣例,接口的名字以大寫字母"I"開頭。下面的代碼是C#接口的一個例子,它與Java中的接口完全一樣: inte
12、rface IShape void Draw ( ) ; 如果你從兩個或者兩個以上的接口派生,父接口的名字列表用逗號分隔,如下面的代碼所示: interface INewInterface: IParent1, IParent2 然而,與Java不同,C#中的接口不能包含域(Field)。另外還要注意,在C#中,接口內(nèi)的所有方法默認(rèn)都是公用方法。在Java中,方法定義可以帶有public修飾符(即使這并非必要),但在C#中,顯式為接口的方法指定public修飾符是非法的。例如,下面的C#接口將產(chǎn)生一個編譯錯誤。 interface IShape public void Draw(
13、 ) ; 下面的例子定義了一個名為IControl 的接口,接口中包含一個成員方法Paint:interface IControl void Paint( ) ; 在下例中,接口 IInterface從兩個基接口 IBase1 和 IBase2 繼承:interface IInterface: IBase1, IBase2 void Method1( ) ;void Method2( ) ; 接口可由類實現(xiàn)。實現(xiàn)的接口的標(biāo)識符出現(xiàn)在類的基列表中。例如:class Class1: Iface1, Iface2 / class 成員。 類的基列表同時包含基類和接口時,列表中
14、首先出現(xiàn)的是基類。例如:class ClassA: BaseClass, Iface1, Iface2 / class成員。 以下的代碼段定義接口IFace,它只有一個方法:interface IFace void ShowMyFace( ) ; 不能從這個定義實例化一個對象,但可以從它派生一個類。因此,該類必須實現(xiàn)ShowMyFace抽象方法:class CFace:IFacepublic void ShowMyFace( ) Console.WriteLine(" implementation " ) ; 基接口一個接口可以從零或多個接口繼承,那些被稱為這
15、個接口的顯式基接口。當(dāng)一個接口有比零多的顯式基接口時,那么在接口的定義中的形式為,接口標(biāo)識符后面跟著由一個冒號":"和一個用逗號","分開的基接口標(biāo)識符列表。接口基::接口類型列表說明:1、一個接口的顯式基接口必須至少同接口本身一樣可訪問。例如,在一個公共接口的基接口中指定一個私有或內(nèi)部的接口是錯誤的。2、一個接口直接或間接地從它自己繼承是錯誤的。3、接口的基接口都是顯式基接口,并且是它們的基接口。換句話說,基接口的集合完全由顯式基接口和它們的顯式基接口等等組成。在下面的例子中interface IControl void Paint( ) ;inter
16、face 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、一個實現(xiàn)了接口的類或結(jié)構(gòu)也隱含地實現(xiàn)了所有接口的基接口。接口主
17、體一個接口的接口主體定義接口的成員。interface-body: interface-member-declarationsopt 定義接口主要是定義接口成員,請看下一節(jié)-定義接口成員。第三節(jié) 定義接口成員接口可以包含一個和多個成員,這些成員可以是方法、屬性、索引指示器和事件,但不能是常量、域、操作符、構(gòu)造函數(shù)或析構(gòu)函數(shù),而且不能包含任何靜態(tài)成員。接口定義創(chuàng)建新的定義空間,并且接口定義直 接包含的接口成員定義將新成員引入該定義空間。說明:1、接口的成員是從基接口繼承的成員和由接口本身定義的成員。2、接口定義可以定義零個或多個成員。接口的成員必須是方法、屬性、事件或索引器。接口不能包含常數(shù)、字
18、段、運算符、實例構(gòu)造函數(shù)、析構(gòu)函數(shù)或類型,也不能包含任何種類的靜態(tài)成員。3、定義一個接口,該接口對于每種可能種類的成員都包含一個:方法、屬性、事件和索引器。 4、接口成員默認(rèn)訪問方式是public。接口成員定義不能包含任何修飾符,比如成員定義前不能加abstract,public,protected,internal,private,virtual,override 或static 修飾符。5、接口的成員之間不能相互同名。繼承而來的成員不用再定義,但接口可以定義與繼承而來的成員同名的成員,這時我們說接口成員覆蓋了繼承而來的成員,這不會導(dǎo)致錯誤,但編譯器會給出一個警告。關(guān)閉警告提示的方式是在成員
19、定義前加上一個new關(guān)鍵字。但如果沒有覆蓋父接口中的成員,使用new 關(guān)鍵字會導(dǎo)致編譯器發(fā)出警告。 6、方法的名稱必須與同一接口中定義的所有屬性和事件的名稱不同。此外,方法的簽名必須與同一接口中定義的所有其他方法的簽名不同。 7、屬性或事件的名稱必須與同一接口中定義的所有其他成員的名稱不同。 8、一個索引器的簽名必須區(qū)別于在同一接口中定義的其他所有索引器的簽名。 9、接口方法聲明中的屬性(attributes), 返回類型(return-type), 標(biāo)識符(identifier), 和形式參數(shù)列表(formal-parameter-lis)與一個類的方法聲明中的那些有相同的意義。一個接口方法
20、聲明不允許指定一個方法主體,而聲明通常用一個分號結(jié)束。10、接口屬性聲明的訪問符與類屬性聲明的訪問符相對應(yīng),除了訪問符主體通常必須用分號。因此,無論屬性是讀寫、只讀或只寫,訪問符都完全確定。11、接口索引聲明中的屬性(attributes), 類型(type), 和形式參數(shù)列表 (formal-parameter-list)與類的索引聲明的那些有相同的意義。下面例子中接口IMyTest包含了索引指示器、事件E、 方法F、 屬性P 這些成員:interface IMyTeststring thisint index get; set; event EventHandler E ;void F(i
21、nt value) ;string P get; set; public delegate void EventHandler(object sender, EventArgs e) ; 下面例子中接口IStringList包含每個可能類型成員的接口:一個方法,一個屬性,一個事件和一個索引。public delegate void StringListEvent(IStringList sender);public interface IStringListvoid Add(string s);int Count get; event StringListEvent Changed;strin
22、g thisint index get; set; 接口成員的全權(quán)名使用接口成員也可采用全權(quán)名(fully qualified name)。接口的全權(quán)名稱是這樣構(gòu)成的。接口名加小圓點"." 再跟成員名比如對于下面兩個接口:interface IControl void Paint( ) ;interface ITextBox: IControl void GetText(string text) ; 其中Paint 的全權(quán)名是IControl.Paint,GetText的全權(quán)名是ITextBox. GetText。當(dāng)然,全權(quán)名中的成員名稱必須是在接口中已經(jīng)定義過的,比如使用
23、ITextBox.Paint.就是不合理的。如果接口是名字空間的成員,全權(quán)名還必須包含名字空間的名稱。namespace Systempublic interface IDataTable object Clone( ) ; 那么Clone方法的全權(quán)名是System. IDataTable.Clone。定義好了接口,接下來就是怎樣訪問接口,請看下一節(jié)-訪問接口第四節(jié)、訪問接口對接口成員的訪問對接口方法的調(diào)用和采用索引指示器訪問的規(guī)則與類中的情況也是相同的。如果底層成員的命名與繼承而來的高層成員一致,那么底層成員將覆蓋同名的高層成員。但由于接口支持多繼承,在多繼承中,如果兩個父接口含有同名的成員
24、,這就產(chǎn)生了二義性(這也正是C#中取消了類的多繼承機(jī)制的原因之一),這時需要進(jìn)行顯式的定義: 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).Coun
25、t = 1; / 正確(IRing)rs).Count(1) ; / 正確調(diào)用IRing.Count 上面的例子中,前兩條語句rs .Count(1)和rs .Count = 1會產(chǎn)生二義性,從而導(dǎo)致編譯時錯誤,因此必須顯式地給rs 指派父接口類型,這種指派在運行時不會帶來額外的開銷。再看下面的例子:using System ;interface IInteger void Add(int i) ;interface IDouble void Add(double d) ;interface INumber: IInteger, IDouble class CMyTest void Test(
26、INumber Num) / Num.Add(1) ; 錯誤Num.Add(1.0) ; / 正確(IInteger)n).Add(1) ; / 正確(IDouble)n).Add(1) ; / 正確 調(diào)用Num.Add(1) 會導(dǎo)致二義性,因為候選的重載方法的參數(shù)類型均適用。但是,調(diào)用Num.Add(1.0) 是允許的,因為1.0 是浮點數(shù)參數(shù)類型與方法IInteger.Add()的參數(shù)類型不一致,這時只有IDouble.Add 才是適用的。不過只要加入了顯式的指派,就決不會產(chǎn)生二義性。接口的多重繼承的問題也會帶來成員訪問上的問題。例如:interface IBase void FWay(i
27、nt 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) ; / 調(diào)用ILeft. FWay(IBase)d). FWay (1) ; / 調(diào)用IBase. FWay(ILeft)d). FWay (1) ; / 調(diào)用ILeft. FWay(IRight)d). FWay (1) ; / 調(diào)用IBase. FWay 上
28、例中,方法IBase.FWay在派生的接口ILeft中被Ileft的成員方法FWay覆蓋了。所以對d. FWay (1)的調(diào)用實際上調(diào)用了。雖然從IBase-> IRight-> IDerived這條繼承路徑上來看,ILeft.FWay方法是沒有被覆蓋的。我們只要記住這一點:一旦成員被覆蓋以后,所有對其的訪問都被覆蓋以后的成員"攔截"了。類對接口的實現(xiàn)前面我們已經(jīng)說過,接口定義不包括方法的實現(xiàn)部分。接口可以通過類或結(jié)構(gòu)來實現(xiàn)。我們主要講述通過類來實現(xiàn)接口。用類來實現(xiàn)接口時,接口的名稱必須包含在類定義中的基類列表中。下面的例子給出了由類來實現(xiàn)接口的例子。其中ISe
29、quence 為一個隊列接口,提供了向隊列尾部添加對象的成員方法Add( ),IRing 為一個循環(huán)表接口,提供了向環(huán)中插入對象的方法Insert(object obj),方法返回插入的位置。類RingSquence 實現(xiàn)了接口ISequence 和接口IRing。using System ;interface ISequence object Add( ) ;interface ISequence object Add( ) ;interface IRing int Insert(object obj) ;class RingSequence: ISequence, IRingpublic
30、object Add( ) public int Insert(object obj) 如果類實現(xiàn)了某個接口,類也隱式地繼承了該接口的所有父接口,不管這些父接口有沒有在類定義的基類表中列出??聪旅娴睦樱簎sing System ;interface IControl void Paint( );interface ITextBox: IControl void SetText(string text);interface IListBox: IControl void SetItems(string items);interface IComboBox: ITextBox, IListBox
31、 這里, 接口IcomboBox繼承了ItextBox和IlistBox。類TextBox不僅實現(xiàn)了接口ITextBox,還實現(xiàn)了接口ITextBox 的父接口IControl。前面我們已經(jīng)看到,一個類可以實現(xiàn)多個接口。再看下面的例子:interface IDataBound void Bind(Binder b);public class EditBox: Control, IControl, IDataBound public void Paint( );public void Bind(Binder b) . 類EditBox從類Control中派生并且實現(xiàn)了Icontrol
32、和IdataBound。在前面的例子中接口Icontrol中的Paint方法和IdataBound接口中的Bind方法都用類EditBox中的公共成員實現(xiàn)。C#提供一種實現(xiàn)這些方法的可選擇的途徑,這樣可以使執(zhí)行這些的類避免把這些成員設(shè)定為公共的。接口成員可以用有效的名稱來實現(xiàn)。例如,類EditBox可以改作方法Icontrol.Paint和IdataBound.Bind來來實現(xiàn)。 public class EditBox: IControl, IDataBound void IControl.Paint( ) .void IDataBound.Bind(Binder b) . 因為通過外部指派
33、接口成員實現(xiàn)了每個成員,所以用這種方法實現(xiàn)的成員稱為外部接口成員。外部接口成員可以只是通過接口來調(diào)用。例如,Paint方法中EditBox的實現(xiàn)可以只是通過創(chuàng)建Icontrol接口來調(diào)用。class Test static void Main( ) EditBox editbox = new EditBox( );editbox.Paint( ); /錯誤: EditBox 沒有Paint 事件IControl control = editbox;control.Paint( ); / 調(diào)用 EditBox的Paint事件 上例中,類EditBox 從Control 類繼承并同時實現(xiàn)了ICon
34、trol and IDataBound 接口。EditBox 中的Paint 方法來自IControl 接口,Bind 方法來自IDataBound 接口,二者在EditBox 類中都作為公有成員實現(xiàn)。當(dāng)然,在C# 中我們也可以選擇不作為公有成員實現(xiàn)接口。如果每個成員都明顯地指出了被實現(xiàn)的接口,通過這種途徑被實現(xiàn)的接口我們稱之為顯式接口成員(explicit interface member)。 用這種方式我們改寫上面的例子:public class EditBox: IControl, IDataBound void IControl.Paint( ) void IDataBound.Bin
35、d(Binder b) 顯式接口成員只能通過接口調(diào)用。例如:class CTest static void Main( ) EditBox editbox = new EditBox( ) ;editbox.Paint( ) ; /錯誤:不同的方法IControl control = editbox;control.Paint( ) ; /調(diào)用 EditBox的Paint方法 上述代碼中對editbox.Paint( )的調(diào)用是錯誤的,因為editbox 本身并沒有提供這一方法。control.Paint( )是正確的調(diào)用方式。注釋:接口本身不提供所定義的成員的實現(xiàn),它僅僅說明這些成員,這些成
36、員必須依靠實現(xiàn)接口的類或其它接口的支持。知道了怎樣訪問接口,我們還要知道怎樣實現(xiàn)接口,要實現(xiàn)C#的接口,請看下一節(jié)-實現(xiàn)接口 第五節(jié)、實現(xiàn)接口1、顯式實現(xiàn)接口成員為了實現(xiàn)接口,類可以定義顯式接口成員執(zhí)行體(Explicit interface member implementations)。顯式接口成員執(zhí)行體可以是一個方法、一個屬性、一個事件或者是一個索引指示器的定義,定義與該成員對應(yīng)的全權(quán)名應(yīng)保持一致。using System ;interface ICloneable object Clone( ) ;interface IComparable int CompareTo(object o
37、ther) ;class ListEntry: ICloneable, IComparable object ICloneable.Clone( ) int IComparable.CompareTo(object other) 上面的代碼中ICloneable.Clone 和IComparable.CompareTo 就是顯式接口成員執(zhí)行體。說明:1、不能在方法調(diào)用、屬性訪問以及索引指示器訪問中通過全權(quán)名訪問顯式接口成員執(zhí)行體。事實上,顯式接口成員執(zhí)行體只能通過接口的實例,僅僅引用接口的成員名稱來訪問。2、顯式接口成員執(zhí)行體不能使用任何訪問限制符,也不能加上abstract, virtual
38、, override或static 修飾符。3、顯式接口成員執(zhí)行體和其他成員有著不同的訪問方式。因為不能在方法調(diào)用、屬性訪問以及索引指示器訪問中通過全權(quán)名訪問,顯式接口成員執(zhí)行體在某種意義上是私有的。但它們又可以通過接口的實例訪問,也具有一定的公有性質(zhì)。4、只有類在定義時,把接口名寫在了基類列表中,而且類中定義的全權(quán)名、類型和返回類型都與顯式接口成員執(zhí)行體完全一致時,顯式接口成員執(zhí)行體才是有效的,例如:class Shape: ICloneable object ICloneable.Clone( ) int IComparable.CompareTo(object other) 使用顯式接口
39、成員執(zhí)行體通常有兩個目的:1、因為顯式接口成員執(zhí)行體不能通過類的實例進(jìn)行訪問,這就可以從公有接口中把接口的實現(xiàn)部分單獨分離開。如果一個類只在內(nèi)部使用該接口,而類的使用者不會直接使用到該接口,這種顯式接口成員執(zhí)行體就可以起到作用。2、顯式接口成員執(zhí)行體避免了接口成員之間因為同名而發(fā)生混淆。如果一個類希望對名稱和返回類型相同的接口成員采用不同的實現(xiàn)方式,這就必須要使用到顯式接口成員執(zhí)行體。如果沒有顯式接口成員執(zhí)行體,那么對于名稱和返回類型不同的接口成員,類也無法進(jìn)行實現(xiàn)。下面的定義是無效的,因為Shape 定義時基類列表中沒有出現(xiàn)接口IComparable。class Shape: IClonea
40、bleobject ICloneable.Clone( ) class Ellipse: Shapeobject ICloneable.Clone( ) 在Ellipse 中定義ICloneable.Clone是錯誤的,因為Ellipse即使隱式地實現(xiàn)了接口ICloneable,ICloneable仍然沒有顯式地出現(xiàn)在Ellipse定義的基類列表中。接口成員的全權(quán)名必須對應(yīng)在接口中定義的成員。如下面的例子中,Paint的顯式接口成員執(zhí)行體必須寫成IControl.Paint。using System ;interface IControlvoid Paint( ) ;interface ITe
41、xtBox: IControlvoid SetText(string text) ;class TextBox: ITextBoxvoid IControl.Paint( ) void ITextBox.SetText(string text) 實現(xiàn)接口的類可以顯式實現(xiàn)該接口的成員。當(dāng)顯式實現(xiàn)某成員時,不能通過類實例訪問該成員,而只能通過該接口的實例訪問該成員。顯式接口實現(xiàn)還允許程序員繼承共享相同成員名的兩個接口,并為每個接口成員提供一個單獨的實現(xiàn)。下面例子中同時以公制單位和英制單位顯示框的尺寸。Box類繼承 IEnglishDimensions和 IMetricDimension
42、s兩個接口,它們表示不同的度量衡系統(tǒng)。兩個接口有相同的成員名 Length 和 Width。程序清單1 DemonInterface.csinterface IEnglishDimensions float Length ( ) ;float Width ( ) ;interface IMetricDimensions float Length ( ) ;float Width ( ) ;class Box : IEnglishDimensions, IMetricDimensions float lengthInches ;float widthInches ;public Box(floa
43、t 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
44、 ;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",
45、 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,Wid
46、th (cm): 50.8代碼討論:如果希望默認(rèn)度量采用英制單位,請正常實現(xiàn) Length 和 Width 這兩個方法,并從 IMetricDimensions 接口顯式實現(xiàn) Length 和 Width 方法:public float Length( ) return lengthInches ;public float Width( )return widthInches;float IMetricDimensions.Length( ) return lengthInches * 2.54f ;float IMetricDimensions.Width( ) return widthIn
47、ches * 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
48、): 0", mDimensions.Width( ) ; 2、繼承接口實現(xiàn)接口具有不變性,但這并不意味著接口不再發(fā)展。類似于類的繼承性,接口也可以繼承和發(fā)展。注意:接口繼承和類繼承不同,首先,類繼承不僅是說明繼承,而且也是實現(xiàn)繼承;而接口繼承只是說明繼承。也就是說,派生類可以繼承基類的方法實現(xiàn),而派生的接口只繼承了父接口的成員方法說明,而沒有繼承父接口的實現(xiàn),其次,C#中類繼承只允許單繼承,但是接口繼承允許多繼承,一個子接口可以有多個父接口。接口可以從零或多個接口中繼承。從多個接口中繼承時,用":"后跟被繼承的接口名字,多個接口名之間用","
49、分割。被繼承的接口應(yīng)該是可以訪問得到的,比如從private 類型或internal 類型的接口中繼承就是不允許的。接口不允許直接或間接地從自身繼承。和類的繼承相似,接口的繼承也形成接口之間的層次結(jié)構(gòu)。請看下面的例子:using System ;interface IControl void Paint( ) ;interface ITextBox: IControl void SetText(string text) ;interface IListBox: IControl void SetItems(string items) ;interface IComboBox: ITextBox
50、, IListBox 對一個接口的繼承也就繼承了接口的所有成員,上面的例子中接口ITextBox和IListBox都從接口IControl中繼承,也就繼承了接口IControl的Paint方法。接口IComboBox從接口ITextBox和IListBox中繼承,因此它應(yīng)該繼承了接口ITextBox的SetText方法和IListBox的SetItems方法,還有IControl的Paint方法。一個類繼承了所有被它的基本類提供的接口實現(xiàn)程序。不通過顯式的實現(xiàn)一個接口,一個派生類不能用任何方法改變它從它的基本類繼承的接口映射。例如,在聲明中interface IControl void Pai
51、nt( );class Control: IControl public void Paint( ) .class TextBox: Control new public void Paint( ) . TextBox 中的方法Paint 隱藏了Control中的方法Paint ,但是沒有改變從Control.Paint 到IControl.Paint 的映射,而通過類實例和接口實例調(diào)用Paint將會有下面的影響Control c = new Control( ) ;TextBox t = new TextBox( ) ;IControl ic = c ;IControl it = t ;c.
52、Paint( ) ; / 影響Control.Paint( ) ;t.Paint( ) ; / 影響TextBox.Paint( ) ;ic.Paint( ) ; / 影響Control.Paint( ) ;it.Paint( ) ; / 影響Control.Paint( ) ; 但是,當(dāng)一個接口方法被映射到一個類中的虛擬方法,派生類就不可能覆蓋這個虛擬方法并且改變接口的實現(xiàn)函數(shù)。例如,把上面的聲明重新寫為interface IControl void Paint( ) ;class Control: IControl public virtual void Paint( ) .class T
53、extBox: Control public override void Paint( ) . 就會看到下面的結(jié)果: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( ); 由于顯式接口成
54、員實現(xiàn)程序不能被聲明為虛擬的,就不可能覆蓋一個顯式接口成員實現(xiàn)程序。一個顯式接口成員實現(xiàn)程序調(diào)用另外一個方法是有效的,而另外的那個方法可以被聲明為虛擬的以便讓派生類可以覆蓋它。例如: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 的實現(xiàn)程序進(jìn)行特殊化。3、重新實現(xiàn)接口我們已經(jīng)介紹過,派生類可以對基類中已經(jīng)定義的成員方法進(jìn)行重載。類似的概念引入到類對接口的實現(xiàn)中來,叫做接口的重實現(xiàn)(re-implementation)。繼承了接口實現(xiàn)的類可以對接口進(jìn)行重實現(xiàn)。這個接口要求是在類定義的基類列表中出現(xiàn)過的。對接口的重實現(xiàn)也必須嚴(yán)格地遵守首次實現(xiàn)接口的規(guī)則,派生的接口映射不會對為接口的重實現(xiàn)所建立的接口映射產(chǎn)生任何影響。下面的代碼給出了接口重實現(xiàn)的例子:interfac
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 原地回遷合同范本
- 體育冠名合同范本
- 合同范例起訴書
- 展會招商渠道合同范本
- 單位簽合同范例
- 合同范本格式 字體
- 冷鏈車輛采購合同范本
- 臨時安置房建設(shè)合同范本
- 樓地面找平合同范本
- 合同范例機(jī)械產(chǎn)品
- 2023風(fēng)力發(fā)電機(jī)組延壽評估技術(shù)規(guī)范
- 鞋業(yè)-品質(zhì)培訓(xùn)
- 小學(xué)思政課《愛國主義教育》
- 瓜豆原理【模型專題】(含答案解析)
- 單價、數(shù)量、總價-教學(xué)課件【A3演示文稿設(shè)計與制作】
- 中小學(xué)生安全教育手冊全面版
- 變電站安裝工程安全風(fēng)險分級管控清單
- DDI-能力解構(gòu)詞典
- 燃?xì)夤艿拦こ瘫O(jiān)理實施細(xì)則
- 安全經(jīng)驗分享之行車安全經(jīng)驗分享
- 忻州市忻府區(qū)康益種植園利用粉煤灰開發(fā)造地項目?環(huán)評報告
評論
0/150
提交評論