




已閱讀5頁,還剩18頁未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
目 錄第3章 對象和類型23.1 類和結(jié)構(gòu)23.2 類成員23.2.1 數(shù)據(jù)成員23.2.2 函數(shù)成員23.2.3 只讀字段143.3 匿名類型163.4 結(jié)構(gòu)163.4.1 結(jié)構(gòu)是值類型173.4.2 結(jié)構(gòu)和繼承183.4.3 結(jié)構(gòu)的構(gòu)造函數(shù)183.5 部分類183.6 靜態(tài)類193.7 Object類203.7.1 System.Object方法203.7.2 ToString()方法203.8 擴(kuò)展方法223.9 小結(jié)22第3章 對象和類型到目前為止,我們介紹了組成C#語言的主要內(nèi)容,包括變量、數(shù)據(jù)類型和程序流語句,并簡要介紹了一個(gè)只包含Main()方法的完整小例子。但還沒有介紹如何把這些內(nèi)容組合在一起,構(gòu)成一個(gè)完整的程序,其關(guān)鍵就在于對類的處理。這就是本章的主題。本章的主要內(nèi)容如下:類和結(jié)構(gòu)的區(qū)別類成員按值和引用傳送參數(shù)方法重載構(gòu)造函數(shù)和靜態(tài)構(gòu)造函數(shù)只讀字段部分類靜態(tài)類Object類,其他類型都從該類派生而來第4章將介紹繼承以及與繼承相關(guān)的特性。提示:本章將討論與類相關(guān)的基本語法,但假定您已經(jīng)熟悉了使用類的基本原則,例如,知道構(gòu)造函數(shù)和屬性的含義,因此我們只是大致論述如何把這些原則應(yīng)用于C#代碼。本章介紹的這些概念不一定得到了大多數(shù)面向?qū)ο笳Z言的支持。例如對象構(gòu)造函數(shù)是您熟悉的、使用廣泛的一個(gè)概念,但靜態(tài)構(gòu)造函數(shù)就是C#的新增內(nèi)容,所以我們將解釋靜態(tài)構(gòu)造函數(shù)的工作原理。3.1 類和結(jié)構(gòu)類和結(jié)構(gòu)實(shí)際上都是創(chuàng)建對象的模板,每個(gè)對象都包含數(shù)據(jù),并提供了處理和訪問數(shù)據(jù)的方法。類定義了每個(gè)類對象(稱為實(shí)例)可以包含什么數(shù)據(jù)和功能。例如,如果一個(gè)類表示一個(gè)顧客,就可以定義字段CustomerID、FirstName、LastName和Address,以包含該顧客的信息。還可以定義處理存儲在這些字段中的數(shù)據(jù)的功能。接著,就可以實(shí)例化這個(gè)類的對象,以表示某個(gè)顧客,并為這個(gè)實(shí)例設(shè)置這些字段,使用其功能。class PhoneCustomerpublic const string DayOfSendingBill =Monday;public int CustomerID;public string FirstName;public string LastName;結(jié)構(gòu)與類的區(qū)別是它們在內(nèi)存中的存儲方式(類是存儲在堆(heap)上的引用類型,而結(jié)構(gòu)是存儲在堆棧(stack)上的值類型)、訪問方式和一些特征(如結(jié)構(gòu)不支持繼承)。較小的數(shù)據(jù)類型使用結(jié)構(gòu)可提高性能。但在語法上,結(jié)構(gòu)與類非常相似,主要的區(qū)別是使用關(guān)鍵字struct代替class來聲明結(jié)構(gòu)。例如,如果希望所有的PhoneCustomer實(shí)例都存儲在堆棧上,而不是存儲在托管堆上,就可以編寫下面的語句:struct PhoneCustomerStructpublic const string DayOfSendingBill = Monday;public int CustomerID;public string FirstName;public string LastName;對于類和結(jié)構(gòu),都使用關(guān)鍵字new來聲明實(shí)例:這個(gè)關(guān)鍵字創(chuàng)建對象并對其進(jìn)行初始化。在下面的例子中,類和結(jié)構(gòu)的字段值都默認(rèn)為0:PhoneCustomer myCustomer = new PhoneCustomer(); /works for a classPhoneCustomerStruct myCustomer2 = new PhoneCustomerStruct(); / works for a struct在大多數(shù)情況下,類要比結(jié)構(gòu)常用得多。因此,我們先討論類,然后指出類和結(jié)構(gòu)的區(qū)別,以及選擇使用結(jié)構(gòu)而不使用類的特殊原因。但除非特別說明,否則就可以假定用于類的代碼也適用于結(jié)構(gòu)。3.2 類成員類中的數(shù)據(jù)和函數(shù)稱為類的成員。Microsoft的正式術(shù)語對數(shù)據(jù)成員和函數(shù)成員進(jìn)行了區(qū)分。除了這些成員外,類還可以包含嵌套的類型(例如其他類)。類中的所有成員都可以聲明為public(此時(shí)可以在類的外部直接訪問它們)或private(此時(shí),它們只能由類中的其他代碼來訪問)。與Visual Basic、C+和Java一樣,C#在這個(gè)方面還有變化,例如protected(表示成員僅能由該成員所在的類及其派生類訪問),第4章將詳細(xì)解釋各種訪問級別。3.2.1 數(shù)據(jù)成員數(shù)據(jù)成員包含了類的數(shù)據(jù)- 字段、常量和事件。數(shù)據(jù)成員可以是靜態(tài)數(shù)據(jù)(與整個(gè)類相關(guān))或?qū)嵗龜?shù)據(jù)(類的每個(gè)實(shí)例都有它自己的數(shù)據(jù)副本)。通常,對于面向?qū)ο蟮恼Z言,類成員總是實(shí)例成員,除非用static進(jìn)行了顯式的聲明。字段是與類相關(guān)的變量。在前面的例子中已經(jīng)使用了PhoneCustomer類中的字段。一旦實(shí)例化PhoneCustomer對象,就可以使用語法Object.FieldName來訪問這些字段:PhoneCustomer Customer1 = new PhoneCustomer();Customer1.FirstName = Simon;常量與類的關(guān)聯(lián)方式同變量與類的關(guān)聯(lián)方式一樣。使用const關(guān)鍵字來聲明常量。如果它們聲明為public,就可以在類的外部訪問。class PhoneCustomerpublic const string DayOfSendingBill = Monday;public int CustomerID;public string FirstName;public string LastName;事件是類的成員,在發(fā)生某些行為(例如改變類的字段或?qū)傩?,或者進(jìn)行了某種形式的用戶交互操作)時(shí),它可以讓對象通知調(diào)用程序??蛻艨梢园^事件處理程序的代碼來響應(yīng)該事件。第7章將詳細(xì)介紹事件。3.2.2 函數(shù)成員函數(shù)成員提供了操作類中數(shù)據(jù)的某些功能,包括方法、屬性、構(gòu)造函數(shù)和終結(jié)器(finalizer)、運(yùn)算符以及索引器。方法是與某個(gè)類相關(guān)的函數(shù),它們可以是實(shí)例方法,也可以是靜態(tài)方法。實(shí)例方法處理類的某個(gè)實(shí)例,靜態(tài)方法提供了更一般的功能,不需要實(shí)例化一個(gè)類(例如Console. WriteLine()方法)。下一節(jié)介紹方法。屬性是可以在客戶機(jī)上訪問的函數(shù)組,其訪問方式與訪問類的公共字段類似。C#為讀寫類上的屬性提供了專用語法,所以不必使用那些名稱中嵌有Get或Set的偷工減料的方法。因?yàn)閷傩缘倪@種語法不同于一般函數(shù)的語法,在客戶代碼中,虛擬的對象被當(dāng)做實(shí)際的東西。構(gòu)造函數(shù)是在實(shí)例化對象時(shí)自動調(diào)用的函數(shù)。它們必須與所屬的類同名,且不能有返回類型。構(gòu)造函數(shù)用于初始化字段的值。終結(jié)器類似于構(gòu)造函數(shù),但是在CLR檢測到不再需要某個(gè)對象時(shí)調(diào)用。它們的名稱與類相同,但前面有一個(gè)符號。C+程序員應(yīng)注意,終結(jié)器在C#中比在C+中用得少得多,因?yàn)镃LR會自動進(jìn)行垃圾收集,另外,不可能預(yù)測什么時(shí)候調(diào)用終結(jié)器。第12章將介紹終結(jié)器。運(yùn)算符執(zhí)行的最簡單的操作就是+和-。在對兩個(gè)整數(shù)進(jìn)行相加操作時(shí),嚴(yán)格地說,就是對整數(shù)使用+運(yùn)算符。C#還允許指定把已有的運(yùn)算符應(yīng)用于自己的類(運(yùn)算符重載)。第6章將詳細(xì)論述運(yùn)算符。索引器允許對象以數(shù)組或集合的方式進(jìn)行索引。第6章介紹索引器。1. 方法在Visual Basic、C和C+中,可以定義與類完全不相關(guān)的全局函數(shù),但在C#中不能這樣做。在C#中,每個(gè)函數(shù)都必須與類或結(jié)構(gòu)相關(guān)。注意,正式的C#術(shù)語實(shí)際上區(qū)分了函數(shù)和方法。在這個(gè)術(shù)語中,函數(shù)成員不僅包含方法,而且也包含類或結(jié)構(gòu)的一些非數(shù)據(jù)成員,例如索引器、運(yùn)算符、構(gòu)造函數(shù)和析構(gòu)函數(shù)等,甚至還有屬性。這些都不是數(shù)據(jù)成員,字段、常量和事件才是數(shù)據(jù)成員。(1) 方法的聲明在C#中,定義方法的語法與C風(fēng)格的語言相同,與C+和Java中的語法也相同。與C+的主要語法區(qū)別是,在C#中,每個(gè)方法都單獨(dú)聲明為public或private,不能使用public:塊把幾個(gè)方法定義組合起來。另外,所有的C#方法都在類定義中聲明和定義。在C#中,不能像在C+中那樣把方法的實(shí)現(xiàn)代碼分隔開來。在C#中,方法的定義包括方法的修飾符(例如方法的可訪問性)、返回值的類型,然后是方法名、輸入?yún)?shù)的列表(用圓括號括起來)和方法體(用花括號括起來)。modifiers return_type MethodName(parameters)/ Method body每個(gè)參數(shù)都包括參數(shù)的類型名及在方法體中的引用名稱。但如果方法有返回值,return語句就必須與返回值一起使用,以指定出口點(diǎn),例如:public bool IsSquare(Rectangle rect)return (rect.Height = rect.Width);這段代碼使用了一個(gè)表示矩形的.NET基類System.Drawing.Rectangle。如果方法沒有返回值,就把返回類型指定為void,因?yàn)椴荒苁÷苑祷仡愋汀H绻椒ú粠?shù),仍需要在方法名的后面寫上一對空的圓括號()(就像本章前面的Main()方法)。此時(shí)return語句就是可選的- 當(dāng)?shù)竭_(dá)右花括號時(shí),方法會自動返回。注意方法可以包含任意多個(gè)return語句:public bool IsPositive(int value)if (value 20)/ code here to take error recovery action / (eg. throw an exception)elseforeName = value;注意這里的命名模式。我們采用C#的區(qū)分大小寫模式,使用相同的名稱,但公共屬性采用Pascal大小寫命名規(guī)則,而私有屬性采用camel大小寫命名規(guī)則。一些開發(fā)人員喜歡使用前面有下劃線的字段名_foreName,這會為識別字段提供極大的便利。Visual Basic 6程序員應(yīng)注意,C#不區(qū)分Visual Basic 6中的Set和Let,在C#中,寫入訪問器總是用關(guān)鍵字set標(biāo)識。(1) 只讀和只寫屬性在屬性定義中省略set訪問器,就可以創(chuàng)建只讀屬性。因此,把上面例子中的ForeName變成只讀屬性:private string foreName;public string ForeNamegetreturn foreName;同樣,在屬性定義中省略get訪問器,就可以創(chuàng)建只寫屬性。但是,這是不好的編程方式,因?yàn)檫@可能會使客戶機(jī)代碼的作者感到迷惑。一般情況下,如果要這么做,最好使用一個(gè)方法替代。(2) 屬性的訪問修飾符C#允許給屬性的get和set 訪問器設(shè)置不同的訪問修飾符,所以屬性可以有公共的get訪問器和私有或受保護(hù)的set訪問器。這有助于控制屬性的設(shè)置方式或時(shí)間。在下面的例子中,注意set訪問器有一個(gè)私有訪問修飾符,而get訪問器沒有任何訪問修飾符。這表示get訪問器具有屬性的訪問級別。在get 和 set 訪問器中,必須有一個(gè)具備屬性的訪問級別。如果get訪問器的訪問級別是protected,就會產(chǎn)生一個(gè)編譯錯(cuò)誤,因?yàn)檫@會使兩個(gè)訪問器的訪問級別都不是屬性。public string Namegetreturn _name;set_name = value;(3) 自動實(shí)現(xiàn)的屬性如果屬性的set和get訪問器中沒有任何邏輯,就可以使用自動實(shí)現(xiàn)的屬性。這種屬性會自動實(shí)現(xiàn)基礎(chǔ)成員變量。上例的代碼如下:public string ForeName get; set;不需要聲明private string foreName。編譯器會自動創(chuàng)建它。使用自動實(shí)現(xiàn)的屬性,就不能在屬性設(shè)置中進(jìn)行屬性的有效性驗(yàn)證。所以在上面的例子中,不能檢查foreName是否少于20個(gè)字符。但必須有兩個(gè)訪問器。嘗試把該屬性設(shè)置為只讀屬性,就會出錯(cuò):public string ForeName get; 但是,每個(gè)訪問器的訪問級別可以不同。因此,下面的代碼是合法的:public string ForeName get; private set;(4) 內(nèi)聯(lián)一些開發(fā)人員可能會擔(dān)心,在上一節(jié)中,我們列舉了標(biāo)準(zhǔn)C#編碼方式導(dǎo)致了非常小的函數(shù)的許多情形,例如通過屬性訪問字段,而不是直接訪問字段。這些額外的函數(shù)調(diào)用是否會增加系統(tǒng)開銷,導(dǎo)致性能下降?其實(shí),不需要擔(dān)心這種編程方式會在C#中帶來性能損失。C#代碼會編譯為IL,然后在運(yùn)行期間進(jìn)行正常的JIT編譯,獲得內(nèi)部可執(zhí)行代碼。JIT編譯器可生成高度優(yōu)化的代碼,并在適當(dāng)?shù)臅r(shí)候內(nèi)聯(lián)代碼(即用內(nèi)聯(lián)代碼來替代函數(shù)調(diào)用)。如果某個(gè)方法或?qū)傩缘膱?zhí)行代碼僅是調(diào)用另一個(gè)方法,或返回一個(gè)字段,則該方法或?qū)傩钥隙ㄊ莾?nèi)聯(lián)的。但要注意,在何處內(nèi)聯(lián)代碼的決定完全由CLR做出。我們無法使用像C+中inline這樣的關(guān)鍵字來控制哪些方法是內(nèi)聯(lián)的。3. 構(gòu)造函數(shù)在C#中聲明基本構(gòu)造函數(shù)的語法與在Java 和C+中相同。下面聲明一個(gè)與包含的類同名的方法,但該方法沒有返回類型:public class MyClasspublic MyClass()/ rest of class definition與Java 和 C+相同,沒有必要給類提供構(gòu)造函數(shù),在我們的例子中沒有提供這樣的構(gòu)造函數(shù)。一般情況下,如果沒有提供任何構(gòu)造函數(shù),編譯器會在后臺創(chuàng)建一個(gè)默認(rèn)的構(gòu)造函數(shù)。這是一個(gè)非常基本的構(gòu)造函數(shù),它只能把所有的成員字段初始化為標(biāo)準(zhǔn)的默認(rèn)值(例如,引用類型為空引用,數(shù)字?jǐn)?shù)據(jù)類型為0,bool為false)。這通常就足夠了,否則就需要編寫自己的構(gòu)造函數(shù)。注意:對于C+程序員來說,C#中的基本字段在默認(rèn)情況下初始化為0,而C+中的基本字段不進(jìn)行初始化,不需要像C+那樣頻繁地在C#中編寫構(gòu)造函數(shù)。構(gòu)造函數(shù)的重載遵循與其他方法相同的規(guī)則。換言之,可以為構(gòu)造函數(shù)提供任意多的重載,只要它們的簽名有明顯的區(qū)別即可: public MyClass() / zero-parameter constructor/ construction code public MyClass(int number) / another overload/ construction code 但注意,如果提供了帶參數(shù)的構(gòu)造函數(shù),編譯器就不會自動提供默認(rèn)的構(gòu)造函數(shù),只有在沒有定義任何構(gòu)造函數(shù)時(shí),編譯器才會自動提供默認(rèn)的構(gòu)造函數(shù)。在下面的例子中,因?yàn)槎x了一個(gè)帶單個(gè)參數(shù)的構(gòu)造函數(shù),所以編譯器會假定這是可以使用的唯一構(gòu)造函數(shù),不會隱式地提供其他構(gòu)造函數(shù):public class MyNumberprivate int number;public MyNumber(int number) this.number = number; 上面的代碼還說明,一般使用this關(guān)鍵字區(qū)分成員字段和同名的參數(shù)。如果試圖使用無參數(shù)的構(gòu)造函數(shù)實(shí)例化MyNumber對象,就會得到一個(gè)編譯錯(cuò)誤:MyNumber numb = new MyNumber(); / causes compilation error注意,可以把構(gòu)造函數(shù)定義為private或protected,這樣不相關(guān)的類就不能訪問它們:public class MyNumberprivate int number;private MyNumber(int number) / another overloadthis.number = number; 在這個(gè)例子中,我們并沒有為MyNumber定義任何公共或受保護(hù)的構(gòu)造函數(shù)。這就使MyNumber不能使用new運(yùn)算符在外部代碼中實(shí)例化(但可以在MyNumber上編寫一個(gè)公共靜態(tài)屬性或方法,以進(jìn)行實(shí)例化)。這在下面兩種情況下是有用的:類僅用作某些靜態(tài)成員或?qū)傩缘娜萜鳎虼擞肋h(yuǎn)不會實(shí)例化希望類僅通過調(diào)用某個(gè)靜態(tài)成員函數(shù)來實(shí)例化(這就是所謂對象實(shí)例化的類代理方法)(1) 靜態(tài)構(gòu)造函數(shù)C#的一個(gè)新特征是也可以給類編寫無參數(shù)的靜態(tài)構(gòu)造函數(shù)。這種構(gòu)造函數(shù)只執(zhí)行一次,而前面的構(gòu)造函數(shù)是實(shí)例構(gòu)造函數(shù),只要創(chuàng)建類的對象,它都會執(zhí)行。靜態(tài)構(gòu)造函數(shù)在C+和Visual Basic 6中沒有對應(yīng)的函數(shù)。class MyClassstatic MyClass()/ initialization code/ rest of class definition編寫靜態(tài)構(gòu)造函數(shù)的一個(gè)原因是,類有一些靜態(tài)字段或?qū)傩?,需要在第一次使用類之前,從外部源中初始化這些靜態(tài)字段和屬性。.NET運(yùn)行庫沒有確保靜態(tài)構(gòu)造函數(shù)什么時(shí)候執(zhí)行,所以不要把要求在某個(gè)特定時(shí)刻(例如,加載程序集時(shí))執(zhí)行的代碼放在靜態(tài)構(gòu)造函數(shù)中。也不能預(yù)計(jì)不同類的靜態(tài)構(gòu)造函數(shù)按照什么順序執(zhí)行。但是,可以確保靜態(tài)構(gòu)造函數(shù)至多運(yùn)行一次,即在代碼引用類之前執(zhí)行。在C#中,靜態(tài)構(gòu)造函數(shù)通常在第一次調(diào)用類的成員之前執(zhí)行。注意,靜態(tài)構(gòu)造函數(shù)沒有訪問修飾符,其他C#代碼從來不調(diào)用它,但在加載類時(shí),總是由.NET運(yùn)行庫調(diào)用它,所以像public和private這樣的訪問修飾符就沒有意義了。同樣,靜態(tài)構(gòu)造函數(shù)不能帶任何參數(shù),一個(gè)類也只能有一個(gè)靜態(tài)構(gòu)造函數(shù)。很顯然,靜態(tài)構(gòu)造函數(shù)只能訪問類的靜態(tài)成員,不能訪問實(shí)例成員。注意,無參數(shù)的實(shí)例構(gòu)造函數(shù)可以在類中與靜態(tài)構(gòu)造函數(shù)安全共存。盡管參數(shù)列表是相同的,但這并不矛盾,因?yàn)殪o態(tài)構(gòu)造函數(shù)是在加載類時(shí)執(zhí)行,而實(shí)例構(gòu)造函數(shù)是在創(chuàng)建實(shí)例時(shí)執(zhí)行,所以構(gòu)造函數(shù)的執(zhí)行不會有沖突。如果多個(gè)類都有靜態(tài)構(gòu)造函數(shù),先執(zhí)行哪個(gè)靜態(tài)構(gòu)造函數(shù)是不確定的。此時(shí)靜態(tài)構(gòu)造函數(shù)中的代碼不應(yīng)依賴其他靜態(tài)構(gòu)造函數(shù)的執(zhí)行情況。另一方面,如果靜態(tài)字段有默認(rèn)值,它們就在調(diào)用靜態(tài)構(gòu)造函數(shù)之前指定。下面用一個(gè)例子來說明靜態(tài)構(gòu)造函數(shù)的用法,該例子基于包含用戶設(shè)置的程序(用戶設(shè)置假定存儲在某個(gè)配置文件中)。為了簡單一些,假定只有一個(gè)用戶設(shè)置- BackColor,表示要在應(yīng)用程序中使用的背景色。因?yàn)檫@里不想編寫從外部數(shù)據(jù)源中讀取數(shù)據(jù)的代碼,所以假定該設(shè)置在工作日的背景色是紅色,在周末的背景色是綠色。程序僅在控制臺窗口中顯示設(shè)置- 但這足以說明靜態(tài)構(gòu)造函數(shù)是如何工作的。namespace Wrox.ProCSharp.StaticConstructorSamplepublic class UserPreferencespublic static readonly Color BackColor; static UserPreferences()DateTime now = DateTime.Now;if (now.DayOfWeek = DayOfWeek.Saturday | now.DayOfWeek = DayOfWeek.Sunday)BackColor = Color.Green;elseBackColor = Color.Red; private UserPreferences()這段代碼說明了顏色設(shè)置如何存儲在靜態(tài)變量中,該靜態(tài)變量在靜態(tài)構(gòu)造函數(shù)中進(jìn)行初始化。把這個(gè)字段聲明為只讀類型,表示其值只能在構(gòu)造函數(shù)中設(shè)置。本章后面將詳細(xì)介紹只讀字段。這段代碼使用了Microsoft在Framework類庫中支持的兩個(gè)有用的結(jié)構(gòu)System.DateTime和System.Drawing.Color。DateTime結(jié)構(gòu)實(shí)現(xiàn)了靜態(tài)屬性Now和實(shí)例屬性DayOfWeek,Now屬性返回當(dāng)前的時(shí)間,DayOfWeek屬性可以計(jì)算出某個(gè)日期是星期幾。Color(詳見第33章)用于存儲顏色,它實(shí)現(xiàn)了各種靜態(tài)屬性,例如本例使用的Red和Green,返回常用的顏色。為了使用Color結(jié)構(gòu),需要在編譯時(shí)引用System.Drawing.dll程序集,且必須為System.Drawing命名空間添加一個(gè)using語句:using System; using System.Drawing;用下面的代碼測試靜態(tài)構(gòu)造函數(shù): class MainEntryPointstatic void Main(string args)Console.WriteLine(User-preferences: BackColor is: + UserPreferences.BackColor.ToString();編譯并運(yùn)行這段代碼,會得到如下結(jié)果:StaticConstructor.exeUser-preferences: BackColor is: Color Red當(dāng)然,如果在周末執(zhí)行代碼,顏色設(shè)置就是Green。(2) 從其他構(gòu)造函數(shù)中調(diào)用構(gòu)造函數(shù)有時(shí),在一個(gè)類中有幾個(gè)構(gòu)造函數(shù),以容納某些可選參數(shù),這些構(gòu)造函數(shù)都包含一些共同的代碼。例如,下面的情況:class Carprivate string description;private uint nWheels;public Car(string model, uint nWheels)this.description = description;this.nWheels = nWheels;public Car(string description)this.description = description;this.nWheels = 4;/ etc. 這兩個(gè)構(gòu)造函數(shù)初始化了相同的字段,顯然,最好把所有的代碼放在一個(gè)地方。C#有一個(gè)特殊的語法,稱為構(gòu)造函數(shù)初始化器,可以實(shí)現(xiàn)此目的:class Carprivate string description;private uint nWheels; public Car(string description, uint nWheels)this.description = description;this.nWheels = nWheels; public Car(string description) : this(model, 4)/ etc 這里,this關(guān)鍵字僅調(diào)用參數(shù)最匹配的那個(gè)構(gòu)造函數(shù)。注意,構(gòu)造函數(shù)初始化器在構(gòu)造函數(shù)之前執(zhí)行?,F(xiàn)在假定運(yùn)行下面的代碼:Car myCar = new Car(Proton Persona);在本例中,在帶一個(gè)參數(shù)的構(gòu)造函數(shù)執(zhí)行之前,先執(zhí)行帶2個(gè)參數(shù)的構(gòu)造函數(shù)(但在本例中,因?yàn)閹б粋€(gè)參數(shù)的構(gòu)造函數(shù)沒有代碼,所以沒有區(qū)別)。C#構(gòu)造函數(shù)初始化符可以包含對同一個(gè)類的另一個(gè)構(gòu)造函數(shù)的調(diào)用(使用前面介紹的語法),也可以包含對直接基類的構(gòu)造函數(shù)的調(diào)用(使用相同的語法,但應(yīng)使用base關(guān)鍵字代替this)。初始化符中不能有多個(gè)調(diào)用。在C#中,構(gòu)造函數(shù)初始化符的語法類似于C+中的構(gòu)造函數(shù)初始化列表,但C+開發(fā)人員要注意,除了語法類似之外,C#初始化符所包含的代碼遵循完全不同的規(guī)則??梢允褂肅+初始化列表指定成員變量的初始值,或調(diào)用基類構(gòu)造函數(shù),而C#初始化符中的代碼只能調(diào)用另一個(gè)構(gòu)造函數(shù)。這就要求C#類在構(gòu)造時(shí)遵循嚴(yán)格的順序,但C+就沒有這個(gè)要求。這個(gè)問題詳見第4章,那時(shí)就會看到,C#強(qiáng)制遵循的順序只不過是良好的編程習(xí)慣而已。3.2.3 只讀字段常量的概念就是一個(gè)包含不能修改的值的變量,常量是C#與大多數(shù)編程語言共有的。但是,常量不必滿足所有的要求。有時(shí)可能需要一些變量,其值不應(yīng)改變,但在運(yùn)行之前其值是未知的。C#為這種情形提供了另一個(gè)類型的變量:只讀字段。readonly關(guān)鍵字比const靈活得多,允許把一個(gè)字段設(shè)置為常量,但可以執(zhí)行一些運(yùn)算,以確定它的初始值。其規(guī)則是可以在構(gòu)造函數(shù)中給只讀字段賦值,但不能在其他地方賦值。只讀字段還可以是一個(gè)實(shí)例字段,而不是靜態(tài)字段,類的每個(gè)實(shí)例可以有不同的值。與const字段不同,如果要把只讀字段設(shè)置為靜態(tài),就必須顯式聲明。如果有一個(gè)編輯文檔的MDI程序,因?yàn)橐?,需要限制可以同時(shí)打開的文檔數(shù)?,F(xiàn)在假定要銷售該軟件的不同版本,而且顧客可以升級他們的版本,以便同時(shí)打開更多的文檔。顯然,不能在源代碼中對最大文檔數(shù)進(jìn)行硬編碼,而是需要一個(gè)字段表示這個(gè)最大文檔數(shù)。這個(gè)字段必須是只讀的-每次安裝程序時(shí),從注冊表鍵或其他文件存儲中讀取。代碼如下所示: public class DocumentEditorpublic static readonly uint MaxDocuments; static DocumentEditor()MaxDocuments = DosomethingToFindOutMaxNumber();在本例中,字段是靜態(tài)的,因?yàn)槊看芜\(yùn)行程序的實(shí)例時(shí),只需存儲最大文檔數(shù)一次。這就是在靜態(tài)構(gòu)造函數(shù)中初始化它的原因。如果只讀字段是一個(gè)實(shí)例字段,就要在實(shí)例構(gòu)造函數(shù)中初始化它。例如,假定編輯的每個(gè)文檔都有一個(gè)創(chuàng)建日期,但不允許用戶修改它(因?yàn)檫@會覆蓋過去的日期)。注意,該字段也是公共的,我們不需要把只讀字段設(shè)置為私有,因?yàn)榘凑斩x,它們不能在外部修改(這個(gè)規(guī)則也適用于常量)。如前所述,日期用基類System.DateTime表示。下面的代碼使用帶有3個(gè)參數(shù)(年份、月份和月份中的日)的System.DateTime構(gòu)造函數(shù),可以從MSDN文檔中找到這個(gè)構(gòu)造函數(shù)和其他DateTime構(gòu)造函數(shù)的更多信息。 public class Documentpublic readonly DateTime CreationDate; public Document()/ Read in creation date from file. Assume result is 1 Jan 2002/ but in general this can be different for different instances/ of the class CreationDate = new DateTime(2002, 1, 1);在上面的代碼中,CreationDate和MaxDocuments的處理方式與其他字段相同,但因?yàn)樗鼈兪侵蛔x的,所以不能在構(gòu)造函數(shù)外部賦值:void SomeMethod()MaxDocuments = 10;/ compilation error here. MaxDocuments is readonly還要注意,在構(gòu)造函數(shù)中不必給只讀字段賦值,如果沒有賦值,它的值就是其數(shù)據(jù)類型的默認(rèn)值,或者在聲明時(shí)給它初始化的值。這適用于靜態(tài)和實(shí)例只讀字段。3.3 匿名類型第2章討論了var關(guān)鍵字,用于表示隱式類型化的變量。var與new關(guān)鍵字一起使用時(shí),可以創(chuàng)建匿名類型。匿名類型只是一個(gè)繼承了Object的、沒有名稱的類。該類的定義從初始化器中推斷,類似于隱式類型化的變量。如果需要一個(gè)對象包含某個(gè)人的姓氏、中間名和名字,則聲明如下:var captain = new FirstName = James, MiddleName = T, LastName = Kirk;這會生成一個(gè)包含F(xiàn)irstName、MiddleName和LastName屬性的對象。如果創(chuàng)建另一個(gè)對象,如下所示:var doctor = new FirstName = Leonard, MiddleName = , LastName = McCoy;Captain和doctor的類型就是相同的。例如,可以設(shè)置captain = doctor。如果所設(shè)置的值來自于另一個(gè)對象,初始化器就可以簡化。如果已經(jīng)有一個(gè)包含F(xiàn)irstName、MiddleName和LastName屬性的類,且有一個(gè)該類的實(shí)例person,captain對象就可以初始化為:var captain = new (person.FirstName, person.MidleName, person.LastName);person對象的屬性名應(yīng)投射為新對象名captain。所以captain對象應(yīng)有FirstName、MiddleName和LastName屬性。這些新對象的類型名是未知的。編譯器為類型偽造了一個(gè)名稱,但只有編譯器才能使用它。我們不能也不應(yīng)使用新對象上的任何類型引用,因?yàn)檫@不會得到一致的結(jié)果。3.4 結(jié)構(gòu)前面介紹了類如何封裝程序中的對象,也介紹了如何將它們保存在堆中,通過這種方式可以在數(shù)據(jù)的生存期上獲得很大的靈活性,但性能會有一定的損失。因托管堆的優(yōu)化,這種性能損失比較小。但是,有時(shí)僅需要一個(gè)小的數(shù)據(jù)結(jié)構(gòu)。此時(shí),類提供的功能多于我們需要的功能,由于性能的原因,最好使用結(jié)構(gòu)??纯聪旅娴睦樱篶lass Dimensionspublic double Length;public double Width;上面的示例代碼定義了類Dimensions,它只存儲了一個(gè)項(xiàng)的長度和寬度。假定編寫一個(gè)安排設(shè)備的程序,讓人們試著在計(jì)算機(jī)上重新安排設(shè)備,并存儲每個(gè)設(shè)備項(xiàng)的維數(shù)。使字段變?yōu)楣沧侄?,就會違背編程規(guī)則,但我們實(shí)際上并不需要類的全部功能?,F(xiàn)在只有兩個(gè)數(shù)字,把它們當(dāng)作一對來處理,要比單個(gè)處理方便一些。既不需要很多方法,也不需要從類中繼承,也不希望.NET運(yùn)行庫在堆中遇到麻煩和性能問題,只需存儲
溫馨提示
- 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)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 安全試題分類及答案圖片
- 游戲化教學(xué)在科學(xué)探究課程中的創(chuàng)新應(yīng)用報(bào)告
- 2025年數(shù)字貨幣監(jiān)管政策對金融監(jiān)管機(jī)制的影響研究報(bào)告
- 周末安全提醒課件
- 周總理主題班會課件
- 走進(jìn)民族英雄教育
- 助力冬奧班會課件
- 湖南省衡陽市耒陽市2025年八下英語期末學(xué)業(yè)水平測試模擬試題含答案
- 中國元素英文課件
- 中國傳統(tǒng)食品的加工
- 2024年杭州市臨安區(qū)事業(yè)單位統(tǒng)一招聘真題
- C語言程序設(shè)計(jì)基礎(chǔ)知到智慧樹期末考試答案題庫2025年石河子大學(xué)
- 黨建考試試題及答案國企
- 小學(xué)圖書館面試題及答案
- 客運(yùn)行業(yè)事故隱患內(nèi)部報(bào)告獎勵管理制度2025
- 快消品包裝2025年可再生資源利用現(xiàn)狀與前景報(bào)告
- 縱隔腫物護(hù)理
- 房屋建筑與市政工程重大事故安全隱患判定標(biāo)準(zhǔn)解讀課件
- DB43-T 1267-2023 機(jī)動車檢驗(yàn)機(jī)構(gòu)建設(shè)和運(yùn)行管理規(guī)范
- 公司稅務(wù)注銷協(xié)議書
- 2025年人力資源管理專業(yè)期末考試卷及答案
評論
0/150
提交評論