C#—類型和欄位

來源:互聯網
上載者:User

     現在總算是進展到OOP最重要的類型了,感覺很興奮但又困惑,因為C#中有很多與其他OOP語言像是java大不相同的處理。

1.可見度

      C#中的可見度很多與java重疊並且意義相同,但有一個特別的internal(internal其實並不特別)。internal表示僅對定義程式集(assembly)中的所有代碼可見,至於其他程式集不可見。我的第一眼感覺就是java的預設存取權限,即包存取權限,至少它們是類似的。事實上,CLR中的程式集的確對應包,因為它的定義就是一個或多個模組/資源檔的邏輯性分組,而且是重用,安全性及版本控制的最小單元,這些都符合包的特點。正如包存取權限是java的預設許可權一樣,C#的預設許可權就是internal。

      在C#中,當我們在衍生類別中覆寫基類的抽象方法或虛方法時,我們不能修改它們的可見度,就算是放寬可見度也不行(在java中,這是允許的)。

2.靜態類

      靜態類的唯一作用就是將一組相關成員組合到一起,其實也就是靜態成員,因為靜態類無法訪問執行個體成員,它並沒有this引用。我們可以將一個類聲明為靜態類,但是結構不行,雖然結構和類非常相似。靜態類直接繼承自System.Object,因為繼承自其他類是枉然的,它根本就無法建立對象執行個體。靜態類還不能實現任何介面,同樣也是因為只有使用對象執行個體時才能發揮介面的作用。靜態類中的所有成員都是靜態,原因前面已經講過了。靜態類也不能作為欄位,方法參數或局部變數使用,因為它們預設都代表引用一個執行個體變數。靜態類在編譯器中標記為abstract(抽象)和sealed(密封),這是值得注意的。

     很少使用靜態類,像是java也比較少,因為定義一個類,更多是為了封裝資料和行為,並提供提供者,但靜態類根本就是一個封閉的集合,就像前面講的,它只是為了封裝靜態成員而已。

3.部分類別

     關鍵字partial非常神奇,第一次接觸這個關鍵字以及瞭解它的用途之後,我對C#的包容性真的很震驚,它似乎就是一個集合體,把很多東西都攪合在一起。

     partial關鍵字告訴編譯器,這個類,結構或者介面的定義源碼可能要分散到一個或多個原始碼中檔案中。也許我們會很奇怪:為什麼要將我們的源碼分散到多個檔案中呢?原因有以下幾個方面:

    1.原始碼控制:程式員可以將一個類型的源碼從一個源碼控制系統中籤出(check out)進行修改,如果將類型的源碼分散到多個源碼檔案中,就能使多名程式員同時修改單互不影響。

   2.在同一個檔案中,將一個類型或結構分解成不同的邏輯單元:這適合測試類型的功能,我們可以在一個源碼檔案中反覆聲明同一個部分型別,然後在這個類型的多個部分實現不同功能,然後測試它的運行情況。我們可以選擇注釋掉某個部分,或者是用另一個部分來代替它。

  3.代碼拆分:如果熟悉ASP.Net的同學,對拆分一定很熟悉,是的,就是這個拆分。我們在ASP.Net中,經常會將某個組件放進我們的源碼中,然後我們就會發現,該組件的代碼竟然插入到我們的源碼中,如果只是插入,那還沒什麼,但是我們點擊拆分視窗,就可以查看我們的源碼的運行情況。這就是利用了partial關鍵字所起到的神奇作用,不信,大家在使用ASP.Net的時候,可以看看整個源碼。

    partial在組件軟體編程(Component Software Programming,CSP)發揮了很大的作用,同時它也也是OOP思想的一個極佳體現。

4.其他關鍵字

     其他關鍵字像是virtual,new我們都很熟悉(對於virtual由於之前學C++的時候不紮實,所以在寫C#常式的時候犯了錯誤,以為它是java的abstract,沒有寫方法體),virtual表明該方法可以被衍生類別覆寫(override方法也可以,因為它本身就是一個virtual或abstract方法的覆寫版本),而且C#要求覆寫方法時必須註明override(java並不需要,但我們需要添加一個標籤@Override提醒這是基類的覆寫版本),而new在C#中卻有新的用法:

public new void Show(){}public new String name = "";

      它們表明,這是衍生類別自己的欄位和方法,而不是基類的。這種情況適合我們在衍生類別中定義與基類同名的方法或欄位,如果沒有這個new聲明,預設採用基類的方法和欄位,但編譯器會提出警告,因為同名的方法或欄位肯定是為了重新定義(不同於覆寫,C#不支援非虛方法和欄位的覆寫),我們完全可以直接使用基類的方法和欄位。
     前面提到的sealed,表示該類型不能被派生,它就像java的final。它並不僅僅用於類型上,連方法也可以,表示我們不想繼承自該類的類型再覆寫該方法 。

5.類型的設計問題

      類型有這麼多的關鍵字和可見度,導致我們在設計類的時候可能就會有疑問:到底我該怎樣限定它們的可見度和添加合適的關鍵字呢?這個問題其實我在Java那裡就已經有較為基本的認識,這裡結合C#重新說一下。

      C#編譯器預設產生非密封類,但類應該是密封的。原因有下面幾個方面:

      1.版本控制:如果類一開始是密封的,在可預見的未來我們就可以在不破壞相容性的前提下更改為非密封的,但如果類是非密封的,就沒有機會將它改為密封的(如果這樣做,後果很嚴重,因為它後面的一系列衍生類別就會全部陣亡)。java中我還真沒有想過這個問題,因為繼承是擴充舊類的方法,雖然我們更喜歡用介面。

      2.效能:調用虛方法的效能比不上調用非虛方法,因為CLR必須在運行時判斷對象的類型,而如果是密封類的虛方法,編譯器就會當做非虛方法進行調用,因為不可能會有衍生類別覆寫該方法。
      3.安全性和可預測性:將一個方法,屬性或事件設為virtual,是一件很冒險的事,因為基類會喪失對它的行為和狀態的部分控制權,因為衍生類別可以選擇覆寫它們。

      但密封類缺點也是非常明顯的,就是造成類型的使用者巨大的不方便,因為類功能不會一直不變,類型的使用者會想要為該類型添加新的功能。

      所以,這裡就有一個折衷的方法:在實現自己的類時,確保將繼承的所有虛方法(包括System.Object中定義的)都密封,同時,不要定義將來可能對版本控製造成負擔的任何方法,比如受保護方法或虛方法。這種方法適合所有OOP語言,包括java。

      自訂類型的時候,我們還可以遵循一些原則:

      1.除非確定要將該類作為基類使用,並允許衍生類別對它進行特化(specialization,就是我們添加新的行為或屬性),否則就顯式的指定為sealed,而且採用預設的internal,除非我希望公開該類。就算我認為該類有必要被別人繼承,但不想運行對它進行特化,就可以採取上面那個方法。

      2.資料欄位,方法,屬性和事件毫無疑問都設為private,體現良好的資料封裝性。幸好C#編譯器預設就是這樣。

      OOP的世界中,設計類型是我們最大的工作,如何設計一個複用性高,封裝性好,而且耦合度低的類,是一個艱難的工作,甚至可以說是一門藝術,就像OOP大師那樣。

6.欄位

      最後我們簡單的講一下欄位(field)。

     C#的欄位並沒有什麼特別之處,但有關它的修飾符是值得說一下的,那就是readonly。readonly欄位只能在構造器中寫入,也就是對象一旦建立,我們就無法寫入了(可利用反射修改,因為反射可以擷取構造器)。注意,如果是參考型別的欄位標記為readonly,不可改變的是引用而不是引用所指的對象,就像java的final引用。

    

 

    

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.