版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第7章繼承與接口C#程序設(shè)計(jì)教程(第6版)01知識(shí)目標(biāo):使學(xué)生熟悉C#的繼承機(jī)制、多態(tài)性、接口,以及泛型、泛型接口和委托中的協(xié)變、逆變等內(nèi)容。03思政目標(biāo):使學(xué)生樹立既要“繼承”,更要“創(chuàng)新”的理念。02能力目標(biāo):使學(xué)生能夠基于以上知識(shí)進(jìn)行面向?qū)ο蟪绦蛟O(shè)計(jì)的編程。本章學(xué)習(xí)目標(biāo)7.1C#的繼承機(jī)制PARTONE7.1.1繼承的基本知識(shí)繼承(Inheritance)是自動(dòng)地共享、派生類和對(duì)象中的方法與數(shù)據(jù)的機(jī)制。它允許在既有類的基礎(chǔ)上創(chuàng)建新類,新類從既有類中繼承類成員(但構(gòu)造函數(shù)和析構(gòu)函數(shù)不能被繼承),可以重新定義或加進(jìn)新的成員,從而形成類的層次或等級(jí)。一般稱被繼承的類為基類或父類,稱繼承后產(chǎn)生的類為派生類或子類。一個(gè)類的上層可以有基類,下層可以有派生類,這樣就可以形成一種層次結(jié)構(gòu)。層次結(jié)構(gòu)的一個(gè)重要特點(diǎn)是繼承,這種繼承具有傳遞性,即如果C1繼承C2,C2繼承C3,則C1(間接)繼承C3。Y類繼承X類,表明Y類是X類的派生類,X類是Y類中的基類。派生類可以擴(kuò)展它的直接基類,即派生類可以添加新的成員,但不能刪除從基類繼承的成員;派生類可以隱藏基類的成員,如果在派生類中聲明了與基類同名的新成員,那么基類的該成員在派生類中就不能被訪問。一個(gè)類可以有多個(gè)派生類,也可以有多個(gè)基類。一個(gè)類可以直接繼承多個(gè)類,這種繼承方式被稱為多重繼承(MultipleInheritance)。但C#限制一個(gè)類至多只能有一個(gè)基類,即一個(gè)類至多只能直接繼承一個(gè)類,這種繼承方式被稱為單一繼承或簡單繼承。在單一繼承方式下,類的層次結(jié)構(gòu)為樹結(jié)構(gòu),而多重繼承為網(wǎng)狀結(jié)構(gòu)。類之間的繼承關(guān)系,對(duì)于在實(shí)際系統(tǒng)的開發(fā)中迅速建立原型,提高系統(tǒng)的可重用性和可擴(kuò)充性具有十分重要的意義。派生類的聲明格式如下。類修飾符class類名:基類{類體}在類聲明中,通過在類名的后面加上冒號(hào)“:”和基類名來表示繼承。7.1.2base關(guān)鍵字base關(guān)鍵字用于從派生類中訪問基類的成員,它有兩種基本用法。(1)指定創(chuàng)建派生類實(shí)例時(shí)應(yīng)調(diào)用的基類構(gòu)造函數(shù),調(diào)用基類的構(gòu)造函數(shù)完成對(duì)基類成員的初始化工作。(2)在派生類中訪問基類成員。說明:(1)派生類在初始化過程中可以同基類進(jìn)行通信。該程序演示了在派生類的構(gòu)造函數(shù)定義中是如何實(shí)現(xiàn)同基類通信的。冒號(hào)“:”和base關(guān)鍵字用于調(diào)用帶有相應(yīng)參數(shù)的基類的構(gòu)造函數(shù)。在運(yùn)行結(jié)果中,第1行表明基類的構(gòu)造函數(shù)最先被調(diào)用,其參數(shù)是字符串“FormDerived”。(2)對(duì)于基類已有定義的方法,重新定義自己的實(shí)現(xiàn)。Child類可以自己重新定義print()方法的實(shí)現(xiàn),重新定義后將覆蓋Parent類中的print()方法。此后,除非經(jīng)過特別指明,Parent類中的print()方法都不會(huì)被調(diào)用。(3)在Child類的print()方法中,特別指明調(diào)用的是Parent類中的print()方法。方法名前為base關(guān)鍵字,一旦使用base關(guān)鍵字,就可以訪問基類中具有公有或保護(hù)權(quán)限的成員。Child類中的print()方法的運(yùn)行結(jié)果為第3行和第4行。(4)訪問基類成員的另外一種方法是顯示類型轉(zhuǎn)換。在Child類的Main()方法的最后一條語句就是這樣做的,并且派生類是其基類的特例,可以在派生類中進(jìn)行數(shù)據(jù)類型的轉(zhuǎn)換,使其成為基類的一個(gè)實(shí)例。最后一行實(shí)際上執(zhí)行了Parent類中的print()方法。7.1.2base關(guān)鍵字在使用base關(guān)鍵字時(shí),要注意base關(guān)鍵字指的是調(diào)用對(duì)象本身,而不僅是指基類中看到的變量或方法。因此,要注意以下幾點(diǎn)注意事項(xiàng)。通過base關(guān)鍵字不僅可以訪問直接基類中定義的域和方法,還可以訪問間接基類中定義的域和方法。在構(gòu)造方法中調(diào)用基類的構(gòu)造方法時(shí),base()是指直接基類的構(gòu)造方法,而不是指間接基類的構(gòu)造方法,這是因?yàn)闃?gòu)造方法是不能被繼承的。由于base關(guān)鍵字指的是對(duì)象,所以它不能在static環(huán)境中使用,如靜態(tài)域(StaticField)、靜態(tài)方法(StaticMethod)和static構(gòu)造方法。7.1.3覆蓋當(dāng)一個(gè)實(shí)例方法聲明中包含一個(gè)override限定符時(shí),該方法會(huì)用相同的屬性覆蓋被繼承的虛擬方法,此方法被稱為覆蓋方法。在覆蓋方法聲明中,不能包括new、static、virtual或abstract限定符中的任何一個(gè),對(duì)于覆蓋聲明,除非它的下方都是可行的語句,否則編譯時(shí)會(huì)出錯(cuò)。被覆蓋的基本方法都能被定位。被覆蓋的基本方法都是虛擬的、抽象的方法,即被覆蓋的基本方法不能是靜態(tài)的或非虛擬的方法。覆蓋聲明及被覆蓋的基本方法具有相同的聲明訪問性。覆蓋聲明可訪問被覆蓋的基本方法。7.2多態(tài)性PARTTWO多態(tài)性是指在一般類中定義的屬性或行為,被特殊類繼承后,可以具有不同數(shù)據(jù)類型或表現(xiàn)出不同的行為。這使得同一個(gè)屬性或行為在一般類及其各個(gè)特殊類中具有不同的語義。例如,首先定義一個(gè)一般類“幾何圖形”,它具有“繪圖”行為,但這個(gè)行為并沒有具體含義,也就是并不確定執(zhí)行時(shí)畫一個(gè)什么樣的圖(因?yàn)榇藭r(shí)連“幾何圖形”都不確定,當(dāng)然“繪圖”也就無從談起了)。然后定義一些特殊的類,如“橢圓形”和“多邊形”,均繼承一般類“幾何圖形”,因此也就有了“繪圖”行為。接下來,就可以在特殊類中根據(jù)具體需要重新定義“繪圖”,使之分別對(duì)應(yīng)“橢圓形”和“多邊形”的繪圖功能。一般地,多態(tài)性的概念常被解釋為“一個(gè)接口,多種方法”。C#支持兩種類型的多態(tài)性,一種是編譯時(shí)多態(tài)性,在程序編譯時(shí)就可以調(diào)用方法的全部信息,決定如何通過方法重載和運(yùn)算符重載來實(shí)現(xiàn)某一動(dòng)作;另一種是運(yùn)行時(shí)多態(tài)性,在運(yùn)行時(shí)通過繼承和虛成員來動(dòng)態(tài)實(shí)現(xiàn)某一動(dòng)作。由此可見,多態(tài)性的特點(diǎn)大大提高了程序的抽象程度和簡潔性,更重要的是,它最大限度地降低了類和程序模塊之間的耦合性,提高了類模塊的封閉性,使它們不用了解對(duì)方的具體細(xì)節(jié),就可以很好地合作。這個(gè)優(yōu)點(diǎn)對(duì)于程序的設(shè)計(jì)、開發(fā)和維護(hù)都有很大的幫助。7.2.1多態(tài)性的概述非虛方法的執(zhí)行是不變的,不管方法在聲明它的類的實(shí)例中還是在派生類的實(shí)例中被調(diào)用,執(zhí)行都是相同的。但虛方法的執(zhí)行可以被派生類改變,具體實(shí)現(xiàn)是在派生類中重新定義虛方法。在重新定義虛方法時(shí),要求方法名稱、返回值類型、參數(shù)表中的參數(shù)個(gè)數(shù)、類型順序都必須與基類中的虛方法完全一致,而且要在方法聲明中加上override關(guān)鍵字,不能有new、static或virtual修飾符。當(dāng)方法聲明中包含virtual修飾符時(shí),方法就被稱為虛方法;當(dāng)沒有virtual修飾符時(shí),方法就被稱為非虛方法。虛方法定義中不能包含static、abstract或override修飾符。7.2.2虛方法下面通過一個(gè)示例來說明多態(tài)性是如何實(shí)現(xiàn)的?!纠?-6】通過虛方法來實(shí)現(xiàn)多態(tài)性。該程序的運(yùn)行結(jié)果如下。PrintinBase、PrintinDerived、DisplayinBase、DisplayinDerived、PrintinDerived、PrintinDerived、DisplayinBase、DisplayinDerived說明:由于Base類的實(shí)例b被賦予Derived類型的實(shí)例d,因此b.Print()調(diào)用的是基類的還是派生類的Print()方法不是在編譯時(shí)確定的,而是在運(yùn)行時(shí)確定的,即根據(jù)實(shí)例b在某一時(shí)刻所引用的對(duì)象來確定調(diào)用哪個(gè)版本的Print()方法,這體現(xiàn)了多態(tài)性。而對(duì)非虛方法Display()的調(diào)用是在編譯時(shí)確定的,在編譯時(shí)就確定了它與哪個(gè)對(duì)象連接,因此無論實(shí)例b引用哪個(gè)對(duì)象,b.Display()調(diào)用的都是Base類中的Display()方法。7.2.3多態(tài)性的實(shí)現(xiàn)7.3接口PARTTHREE接口聲明屬于類型說明,它聲明了新的接口類型,一般語法格式如下。[接口修飾符]interface接口名[:基類接口名]{
接口的成員;};其中,接口修飾符可以是new、public、protected、internal和private。new修飾符是在嵌套接口中唯一被允許使用的修飾符,它表明可以用相同的名稱隱藏一個(gè)繼承的成員。public、protected、internal和private修飾符用于控制接口的訪問能力。1.聲明一個(gè)接口定義一個(gè)協(xié)議,實(shí)現(xiàn)了某個(gè)接口的類或結(jié)構(gòu)必須符合它的協(xié)議。接口可以從多個(gè)基本接口繼承,類或結(jié)構(gòu)可以實(shí)現(xiàn)多個(gè)接口。接口可以包含方法、屬性、事件和索引指示器,但它不為自己定義的成員提供具體實(shí)現(xiàn),只是指定類中必須被實(shí)現(xiàn)的成員。也可以說,接口是一組包含了函數(shù)原型的數(shù)據(jù)結(jié)構(gòu),通過這組數(shù)據(jù)結(jié)構(gòu),客戶代碼可以調(diào)用組件對(duì)象的功能。7.3.1接口的定義繼承了一個(gè)接口的也就繼承了該接口的所有成員。在本例中,接口ITextBox和接口IListBox都是從接口IControl中繼承的,也就繼承了接口IControl的Paint()方法。接口IComboBox的基本接口是IControl、ITextBox和IListBox,即接口IComboBox繼承了接口IControl的Paint()方法、接口ITextBox的SetText()方法和接口IListBox的SetItems()方法。2.接口的繼承接口具有不變性,但這并不意味著接口不再發(fā)展。類似類的繼承性,接口也可以繼承和發(fā)展,它可以從零個(gè)或多個(gè)接口中繼承。從多個(gè)接口中繼承時(shí),冒號(hào)后緊跟被繼承接口的名字,多個(gè)接口名之間用逗號(hào)分隔。被繼承的接口應(yīng)該是可以被訪問的,即不能繼承private或internal類型的接口。接口不允許直接或間接地從自身繼承。7.3.1接口的定義7.3.2接口的成員1.接口成員的定義接口可以包含一個(gè)或多個(gè)成員,這些成員可以是方法、屬性、事件和索引指示器,但不能是常量、域、操作符、構(gòu)造函數(shù)或析構(gòu)函數(shù),而且不能包含任何靜態(tài)成員?!纠?-8】對(duì)接口中成員的定義。usingSystem;publicdelegatevoidStringListEvent(objectsender,EventArgse);publicinterfaceIMyList{voidAdd(strings);intCount{get;}eventStringListEventChanged;stringthis[intindex]{get;set;}}7.3.2接口的成員在本例中,聲明了所有可能的類型成員,方法、屬性、事件和索引指示器。所有接口成員默認(rèn)都是公有訪問。接口成員聲明中包含任何修飾符都是錯(cuò)誤的,它不能被abstract、public、protected、internal、private、virtual、override或static修飾符聲明。接口成員之間不能同名,繼承而來的成員不用再被聲明。但接口可以定義與繼承而來的成員同名的成員,即接口成員覆蓋了繼承而來的成員。這不會(huì)導(dǎo)致錯(cuò)誤,但編譯器會(huì)給出一個(gè)警告,關(guān)閉警告提示的方式是在成員聲明前加上new關(guān)鍵字。但如果沒有覆蓋父接口中的成員,那么使用new關(guān)鍵字會(huì)導(dǎo)致編譯器發(fā)出警告。2.接口屬性接口屬性用接口屬性聲明來聲明,一般語法格式如下。[接口屬性修飾符]接口屬性類型接口屬性標(biāo)識(shí){
接口屬性訪問器;}接口屬性聲明的訪問器與類屬性聲明的訪問器的用法相同。其中,訪問器可以分為以下幾種。get;set;get;set;set;get;即接口的屬性可以是只讀、只寫或可讀可寫的。3.接口事件接口事件用接口事件聲明來聲明,一般語法格式如下。[接口事件修飾符][new]event類型名接口事件標(biāo)識(shí)符;接口事件聲明了一個(gè)事件。實(shí)現(xiàn)接口事件的類可以通過事件與其他類交流。7.3.2接口的成員4.接口索引接口索引使用接口索引聲明來聲明,一般語法格式如下。[接口索引修飾符][new]類型名this[參數(shù)列表]{接口訪問器};接口索引聲明中的屬性、類型和形式參數(shù)列表與類的索引聲明的內(nèi)容有相同的意義。接口索引聲明的訪問器與類索引聲明的訪問器相對(duì)應(yīng),可以分為以下幾種。get;set;get;set;set;get;即接口的索引可以是只讀、只寫或可讀可寫的。5.對(duì)接口成員的訪問接口方法的調(diào)用規(guī)則和采用索引指示器訪問的規(guī)則與類的有相似之處,如果底層成員的命名與繼承而來的高層成員一致,那么底層成員將覆蓋同名的高層成員。但是接口是支持多繼承的,在多繼承中如果兩個(gè)父接口含有同名的成員那么會(huì)產(chǎn)生二義性,這時(shí)就需要進(jìn)行顯式聲明。7.3.2接口的成員6.接口成員的完全有效名稱使用接口成員時(shí)可以采用其完全有效名稱(fullyqualifiedname)。它是這樣構(gòu)成的,接口名加點(diǎn)“.”,再跟成員名?!纠?-12】定義以下兩個(gè)接口。usingSystem;interfaceIControl{voidPaint();}interfaceITextBox:IControl{voidSetText(stringtext);}其中,Paint()方法的完全有效名稱為IControl.Paint,SetText()的完全有效名稱為ITextBox.SetText。完全有效名稱中的成員名稱必須是在接口中已經(jīng)聲明過的,比如,ITextBox.Paint就不是完全有效名稱。如果接口是命名空間的成員,則完全有效名稱還必須包含命名空間的名稱。7.3.2接口的成員1.類對(duì)接口的實(shí)現(xiàn)接口可以通過類或結(jié)構(gòu)來實(shí)現(xiàn),其實(shí)現(xiàn)方法是類似的。用類來實(shí)現(xiàn)接口時(shí),接口名稱必須包含在類聲明的基類列表中。2.顯式接口成員執(zhí)行體接口還可以通過聲明顯式接口成員執(zhí)行體實(shí)現(xiàn)。顯式接口成員執(zhí)行體可以是方法、屬性、事件或索引指示器的聲明。其聲明與該成員對(duì)應(yīng)的完全有效名稱應(yīng)保持一致。顯式接口成員執(zhí)行體不能使用任何訪問修飾符,也不能使用abstract、virtual、override或static修飾符。7.3.3接口的實(shí)現(xiàn)3.接口映射類必須為在基類列表中列出的所有接口的成員提供具體的實(shí)現(xiàn),在類中定位接口成員的實(shí)現(xiàn)稱為接口映射。接口是通過類實(shí)現(xiàn)的,那么對(duì)于在接口中聲明的每一個(gè)成員都應(yīng)該對(duì)應(yīng)類的一個(gè)成員,這種對(duì)應(yīng)關(guān)系是由接口映射來實(shí)現(xiàn)的。類的成員(A)與其所映射的接口成員(B)之間必須滿足以下條件。(1)如果A和B都是成員方法,那么A和B的名稱、類型、形式參數(shù)列表(包括參數(shù)個(gè)數(shù)和每一個(gè)參數(shù)的類型)都應(yīng)該是一致的。(2)如果A和B都是屬性,那么A和B的名稱、類型應(yīng)當(dāng)一致,并且A和B的訪問器也應(yīng)當(dāng)類似。但如果A不是顯式接口成員執(zhí)行體,則A允許添加自己的訪問器。(3)如果A和B都是事件,那么A和B的名稱、類型應(yīng)當(dāng)一致。(4)如果A和B都是索引指示器,那么A和B的類型、形式參數(shù)列表(包含參數(shù)個(gè)數(shù)和參數(shù)類型)應(yīng)當(dāng)一致,而且A和B的訪問器也應(yīng)當(dāng)類似。但如果A不是顯式接口成員執(zhí)行體,則A允許添加自己的訪問器。7.3.3接口的實(shí)現(xiàn)怎樣確定接口成員由哪一個(gè)類的成員來實(shí)現(xiàn)呢?換句話說,接口成員映射的是哪一個(gè)類的成員呢?假如C類實(shí)現(xiàn)了一個(gè)IInterface接口,Member是接口IInterface中的一個(gè)成員,則此時(shí)Member的映射過程如下。(1)如果C類中存在一個(gè)顯式接口成員實(shí)現(xiàn)體,且該實(shí)現(xiàn)體與接口IInterface及其成員Member相對(duì)應(yīng),則由它來實(shí)現(xiàn)Member成員。(2)如果條件1不滿足,C類中存在一個(gè)非靜態(tài)的公有成員,且該成員與接口成員Member相對(duì)應(yīng),則由它來實(shí)現(xiàn)Member成員。(3)如果條件2仍不滿足,則在C類定義的基類列表中尋找基類D,用基類D來代替類C。(4)重復(fù)步驟1至步驟3,遍歷類C的所有直接基類和非直接基類,直到找到一個(gè)滿足條件的類的成員。(5)如果仍然沒有找到,則報(bào)告錯(cuò)誤。7.3.3接口的實(shí)現(xiàn)4.接口實(shí)現(xiàn)的繼承機(jī)制一個(gè)繼承而來的類會(huì)實(shí)現(xiàn)其基類提供的所有接口,如果不顯式地重新實(shí)現(xiàn)接口,則派生類就無法改變從基類中繼承而來的接口映射。5.接口的重實(shí)現(xiàn)派生類可以對(duì)基類中已經(jīng)定義的成員方法進(jìn)行重載,類似的概念在類對(duì)接口的實(shí)現(xiàn)中叫作接口的重實(shí)現(xiàn)。繼承了接口實(shí)現(xiàn)的類可以對(duì)接口進(jìn)行重實(shí)現(xiàn),要求是這個(gè)接口在類聲明的基類列表中出現(xiàn)過。對(duì)接口的重實(shí)現(xiàn)必須嚴(yán)格遵守首次實(shí)現(xiàn)接口的規(guī)則。派生的接口映射不會(huì)對(duì)接口的重實(shí)現(xiàn)所建立的接口映射產(chǎn)生任何影響。6.抽象類與接口和非抽象類一樣,抽象類也必須提供在基類列表中出現(xiàn)的所有接口成員的實(shí)現(xiàn)。不同的是,抽象類允許將接口的方法映射到抽象的成員方法上。7.3.3接口的實(shí)現(xiàn)6.4泛型、泛型接口和委托中的協(xié)變、逆變PARTFOUR7.4.1泛型、泛型集合List<T>、IEnumerable<T>接口及yieldy語句1.定義泛型泛型是在C#中實(shí)現(xiàn)數(shù)據(jù)類型參數(shù)化的機(jī)制,數(shù)據(jù)類型作為參數(shù)定義一個(gè)新的數(shù)據(jù)類型。通過這種機(jī)制可以編寫出一套接口,該接口基于一個(gè)或多個(gè)假設(shè)的類型,只有在使用這個(gè)接口時(shí)才能確定它真正的類型,其不會(huì)強(qiáng)行對(duì)值類型進(jìn)行裝箱和拆箱,或者對(duì)引用類型進(jìn)行向下強(qiáng)制類型轉(zhuǎn)換,因此程序代碼的性能得到了提高。在C#中,通過使用尖括號(hào)“<>”將類型參數(shù)括起來的方式表示泛型。如以下代碼所示,其中,F(xiàn)XClass是一個(gè)泛型類,<T>表示T是一個(gè)假設(shè)的類型,在FXClass類中,可以認(rèn)為T是已知類型。同樣地,F(xiàn)XFunction()是一個(gè)泛型函數(shù),它也認(rèn)為T是已知類型。classFXClass<T>TFXFunction<T>(Tpara)泛型將類型參數(shù)的概念引入C#中,通過泛型可以最大化地實(shí)現(xiàn)代碼重用,它將代碼類型的指定推遲到客戶端代碼,從而大大提高了集合類的效率。本節(jié)將結(jié)合集合類介紹泛型在C#中的使用,同時(shí)介紹其使用得較多的接口IEnumerable等。定義了泛型類后,在默認(rèn)情況下T可以是任何類型,所以可以用實(shí)際的數(shù)據(jù)類型代替T來聲明某個(gè)要使用的類型。值得注意的是,對(duì)于同一個(gè)泛型定義,不同的類型作為參數(shù)所產(chǎn)生的類型是不同的新類型。如以下代碼所示,intFxCls和objFxCls分別是FXClass類關(guān)于int類型和object類型的兩個(gè)實(shí)例,它們屬于不同的類型,即FXClass<int>和FXClass<object>是兩個(gè)不同的類型。FXClass<int>intFxCls;FXClass<object>objFxCls;當(dāng)泛型需要多個(gè)類型參數(shù)時(shí),多個(gè)參數(shù)類型之間用逗號(hào)“,”分隔,但名字不可相同,且都要在尖括號(hào)“<>”內(nèi),如以下代碼所示。前者需要兩個(gè)類型參數(shù),而后者需要三個(gè)類型參數(shù)。classFX2Class<T,U>classFX3Class<T,U,Y>多個(gè)類型參數(shù)在定義類時(shí),必須給出相同數(shù)量的類型,如以下代碼所示。FX2Class<int,float>fx2Cls;classFX3Class<int,int,float>fx3Cls;另外,如果在定義泛型時(shí),希望被使用的參數(shù)類型是已實(shí)現(xiàn)特定接口的類型,那么可以通過where關(guān)鍵字和冒號(hào)“:”運(yùn)算符指定參數(shù)類型的父類(或接口),所有作為參數(shù)的類都必須是這個(gè)類(或接口)或它的子類。7.4.1泛型、泛型集合List<T>、IEnumerable<T>接口及yieldy語句2.泛型集合類——泛型列表List<T>在.NET類庫中,泛型常用于集合類的實(shí)現(xiàn),.NET類庫提供了很多種集合類,包括ArrayList、List、List<T>、LinkedList<T>、HashTable、HashSet、Dictionary<T>等,這里介紹一個(gè)常見的泛型集合類List<T>。(1)列表是簡單、常見的集合類之一,在.NET類庫中,泛型類List<T>實(shí)現(xiàn)了通過索引訪問強(qiáng)類型的列表。List<T>類的參數(shù)類型T可以是任何可訪問的數(shù)據(jù)類型,值類型和引用類型均可。通過中括號(hào)“[]”運(yùn)算符可以訪問List<T>類的元素(與訪問數(shù)組的方式相同),它的索引也是從0開始計(jì)數(shù)的。List<T>類提供了一個(gè)類似數(shù)組的容器,但是與數(shù)組的固定大小不同,它會(huì)根據(jù)列表中元素的個(gè)數(shù)自動(dòng)調(diào)整列表容量,分配和釋放所占用的資源。值得注意的是,List<T>類的容量往往大于實(shí)際元素的數(shù)量,這是為了防止每次添加和移除元素都進(jìn)行內(nèi)存分配和釋放,從而提升代碼性能。所屬命名空間為System.Collections.Generic。publicclassList<T>:IList<T>,ICollection<T>,IEnumerable<T>,IList,ICollection,IEnumerable//List<T>類是ArrayList類的泛型等效類,使用大小可按需動(dòng)態(tài)增加的數(shù)組來實(shí)現(xiàn)IList<T>泛型接口。7.4.1泛型、泛型集合List<T>、IEnumerable<T>接口及yieldy語句性能注意事項(xiàng):IList<T>類和ArrayList類具有類似的功能,但I(xiàn)List<T>類在大多數(shù)情況下執(zhí)行得更好,類型更安全。如果對(duì)IList<T>類的類型T使用引用類型,則兩個(gè)類的行為是完全相同的。但是,如果對(duì)類型T使用值類型,則需要考慮實(shí)現(xiàn)和裝箱問題。添加到ArrayList類中的任何引用或值類型都將被隱式地向上強(qiáng)制轉(zhuǎn)換為object類型。如果項(xiàng)是值類型的,則必須在將其添加到列表時(shí)進(jìn)行裝箱操作,在檢索時(shí)進(jìn)行取消裝箱操作。強(qiáng)制轉(zhuǎn)換及裝箱和取消裝箱操作都會(huì)降低程序性能;在必須對(duì)大型集合進(jìn)行循環(huán)訪問的情況下,裝箱和取消裝箱操作帶來的影響非常明顯。(2)List<T>類提供一系列成員方法(如Add、Insert、Remove、Sort、Find、ToArray等),可對(duì)列表進(jìn)行添加、插入、移除、排序、查找和將當(dāng)前列表中的元素復(fù)制到新數(shù)組中的操作?!纠?-41】List<T>類的常用方法。List<int>intList; //表示一個(gè)int類型的鏈表intList.Add(34); //添加intList.Remove(34); //刪除intList.RemoveAt(0); //刪除位于某處的元素intList.Count; //鏈表長度除此之外,還有FindAll()、Contains()等方法,以及索引方法intList[0]=23等。List<object>相當(dāng)于System.Collections命名空間中的List。7.4.1泛型、泛型集合List<T>、IEnumerable<T>接口及yieldy語句3.ICollection、IEnumerable及IEnumerable<T>接口(1)C#提供了許多方法來實(shí)現(xiàn)集合。在5.1節(jié)中介紹了標(biāo)準(zhǔn)的C#數(shù)組語法,下面介紹System.Collections命名空間所包含的接口。這些接口為所有的C#集合類型定義了框架。接口ICollection定義了對(duì)所有集合類通用的屬性和方法,被接口IList和IDictionary繼承,由ArrayList、CollectionBase、DictionaryBase、Hashtable、Queue、SortedList和Stack類實(shí)現(xiàn)。接口ICollection的常用屬性如表7-1所示。7.4.1泛型、泛型集合List<T>、IEnumerable<T>接口及yieldy語句(2)IEnumerable接口和IEnumerator接口的基本知識(shí)。接口IEnumerable聲明了一個(gè)支持對(duì)集合進(jìn)行簡單遍歷的方法,大部分表示一個(gè)元素序列或元素集合的類都可實(shí)現(xiàn)這個(gè)接口。IEnumerator接口定義了一些屬性和方法,允許枚舉器對(duì)集合進(jìn)行簡單遍歷,任何作為枚舉器的類都可實(shí)現(xiàn)這個(gè)接口。IEnumerable接口的定義格式如下。publicinterfaceIEnumerableIEnumerable接口有一個(gè)公有實(shí)例方法。IEnumeratorGetEnumerator()GetEnumerator()方法返回一個(gè)用于遍歷集合元素的枚舉器。IEnumerator接口的定義格式如下。publicinterfaceIEnumeratorIEnumerator接口有一個(gè)屬性Current、兩個(gè)方法MoveNext()和Reset()。Current屬性返回集合中的當(dāng)前元素,MoveNext()方法指向集合的下一個(gè)元素,Reset()方法移回集合的初始位置(第一個(gè)元素之前)。7.4.1泛型、泛型集合List<T>、IEnumerable<T>接口及yieldy語句(3)除了IEnumerable接口,還有一個(gè)泛型版本IEnumerable<T>,IEnumerable<T>派生自接口IEnumerable,且添加了返回泛型接口IEnumerator<T>的方法。注意:其中,包含yield語句的方法或?qū)傩苑Q為迭代塊。迭代塊必須聲明為返回接口IEnumerator或IEnumerable,或者這些接口的泛型版本。迭代塊可以包含多條yieldreturn語句(返回集合中的一個(gè)元素,并移動(dòng)到下一個(gè)元素)或停止迭代的yieldbreak語句,但不可以包含return語句。yield語句常常與foreach語句組合使用。7.4.1泛型、泛型集合List<T>、IEnumerable<T>接口及yieldy語句publicvoidDisplay(Shapeo){}現(xiàn)在可以傳遞派生自Shape基類的任意對(duì)象。因?yàn)镽ectangle類派生自Shape基類,所以Rectangle對(duì)象滿足Shape基類的所有要求,編譯器接受該方法調(diào)用。Rectangler=newRectangle{Width=5,Height=2.5};Display(r);方法的返回值類型是逆變的。當(dāng)方法返回一個(gè)Shape對(duì)象時(shí),不能把它賦予Rectangle,因?yàn)镾hape類型的返回值不一定總是矩形Rectangle,而可能是其他參數(shù)碼(如三角形Triangle)。相反地,如果某個(gè)方法像GetRectangle()方法那樣返回一個(gè)Rectangle類型的返回值并賦予某個(gè)Shape類型的變量,則是可行的。publicRectangleGetRectangle();把結(jié)果賦予某個(gè)Shape類型的變量s:Shapes=GetRectangle();在.NET4.0之前,泛型接口是不變的。.NET4.0通過協(xié)變(Covariance)和逆變(Contrav-ariance)為泛型接口與泛型委托添加了一個(gè)重要的擴(kuò)展。協(xié)變和逆變是指對(duì)參數(shù)和返回值的類型進(jìn)行轉(zhuǎn)換。例如,給一個(gè)需要Shape參數(shù)的方法傳送Rectangle參數(shù)碼。下面通過示例來
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 貨運(yùn)物流從業(yè)人員安全教育培訓(xùn)制度
- 財(cái)務(wù)專員制度
- 34-連云港2011年中考物理試題
- 2026年中國航天科技集團(tuán)有限公司第五研究院第五一0所校園招聘參考考試試題附答案解析
- 2026四川遂寧市蓬溪縣公安局招聘警務(wù)輔助人員30人參考考試試題附答案解析
- 2026四川華西乳腺健康醫(yī)學(xué)研究院招聘3人備考考試題庫附答案解析
- 2026重慶涪陵區(qū)武陵山鎮(zhèn)人民政府招聘1人備考考試題庫附答案解析
- 2026廣西崇左市事業(yè)單位招聘1652人參考考試試題附答案解析
- 2026年甘肅省蘭州市城關(guān)區(qū)人民政府雁南街道辦事處公益性崗位招聘?jìng)淇伎荚囋囶}附答案解析
- 2026年淮北市衛(wèi)生健康委員會(huì)直屬醫(yī)療機(jī)構(gòu)公開招聘工作人員13名參考考試題庫附答案解析
- 生產(chǎn)車間文員年終總結(jié)
- 《鯉魚的遇險(xiǎn)》讀書分享
- 融媒體中心黨支部2025年前三季度黨建工作總結(jié)范文
- 從2025上半年宏觀經(jīng)濟(jì)及酒類景氣指數(shù)看酒類發(fā)展趨勢(shì)報(bào)告
- 2025急診監(jiān)護(hù)室CRRT相關(guān)知識(shí)考試試題及答案
- 雨水收集利用方案
- 自動(dòng)扶梯應(yīng)急預(yù)案演練計(jì)劃(3篇)
- 1000立方米高性能聚甲基丙稀酰亞胺(PMI)泡沫新材料技改項(xiàng)目可行性研究報(bào)告模板-立項(xiàng)備案
- 動(dòng)物福利與動(dòng)物倫理課件
- 寧夏科技經(jīng)費(fèi)管理辦法
- 擒敵拳教學(xué)課件
評(píng)論
0/150
提交評(píng)論