首先吐糟一下今天杭州的天氣,真是太熱了!雖然沒有妹子跟我約會,但宅在方寸大的窩裡,也是煩躁不已!
接上一篇《C#基礎之基本類型》
在C#中,一個類型內部可以定義多種成員:常量、字段、實例構造器、類型構造器(靜態構造器)、方法、操作符重載、轉換操作符、屬性、事件、類型。
類型的可見性有public和internal(默認)兩種,前者定義的類型對所有程序集中的所有類型都可見,後者定義的類型只對同一程序集內部的所有類型可見:
PublicClass { } ExplicitlyInternalClass { } ImplicitlyInternalClass { }
成員的可訪問性(按限制從大到小排列):
在C#中,如果沒有顯式聲明成員的可訪問性,編譯器通常默認選擇Private(限制最大的那個),CLR要求接口類型的所有成員都是Public訪問性,C#編譯器知道這一點,因此禁止顯式指定接口成員的可訪問性。同時C#還要求在繼承過程中派生類重寫成員時,不能更改成員的可訪問性(CLR並沒有作這個要求,CLR允許重寫成員時放寬限制)。
靜態類
永遠不需要實例化的類,靜態類中只能有靜態成員。在C#中用static這個關鍵詞定義一個靜態類,但只能應用於class,不能應用於struct,因為CLR總是允許值類型實例化。
C#編譯器對靜態類作了如下限制:
分部類、結構和接口
C#編譯器提供一個partial關鍵字,以允許將一個類、結構或接口定義在多個文件裡。
在編譯時,編譯器自動將類、結構或接口的各部分合並起來。這僅是C#編譯器提供的一個功能,CLR對此一無所知。
常量就是代表一恆定數據值的符號,比如我們將圓周率3.12415926定義成名為PI的常量,使代碼更容易閱讀。而且常量是在編譯時就代入運算的(常量就是一個符號,編譯時編譯器就會將該符號替換成實際值),不會造成任何性能上的損失。但這一點也可能會造成一個版本問題,即假如未來修改了常量所代表的值,那麼用到此常量的地方都要重新編譯(我個人認為這也是常量名稱的由來,我們應該將恆定不變的值定義為常量,以免後期改動時產生版本問題)。下面的示例也驗證了這一點,Test1和Test2方法內部的常量運算在編譯後,就已經運算完成。
從上面示例,我們還能看出一點:常量key和value編譯後是靜態成員,這是因為常量通常與類型關聯而不是與實例關聯,從邏輯上說,常量始終是靜態成員。但對於在方法內部定義的常量,由於作用域的限制,不可能有方法之外的地方引用到這個常量,所以在編譯後,常量被優化了。
字段是一種數據成員,在OOP的設計中,字段通常是用來封裝一個類型的內部狀態,而方法表示的是對這些狀態的一些操作。
在C#中字段可用的修飾符有
這裡要注意的是將一個字段標記為readonly時,不變的是引用,而不是引用的值。示例:
[] chars = [] { , , chars[] = ] = ] = chars = [] { , ,
CLR支持兩種屬性:無參屬性和有參屬性(C#中稱為索引器)。
面向對象設計和編程的重要原則之一就是數據封裝,這意味著字段(封裝對象的內部狀態)永遠不應該公開。因此,CLR提供屬性機制來訪問字段內容(VS中輸入propfull加兩次Tab會為我們自動生成字段和屬性的代碼片斷)。
下面的示例中,Person對象內部有一個表示年齡的字段,如果直接公開這個字段,則不能保存外部不會將age設置為0或1000,這顯然是沒有意義的(也破壞了數據封裝性),所以通過屬性,可以在操作字段時,加一些額外邏輯,以保證數據的有效性。
{ (value > && value <= ) age = { }
編譯上述代碼後,實際上編譯器會將屬性內的get和set訪問器各生成一個方法,方法名稱是get_和set_加上屬性名,所以說屬性的本質是方法。
如果只是為了封裝一個字段而創建一個屬性,C#還為我們提供了一種更簡單的語法,稱為自動實現的屬性(AIP)。下面是一個示例(在VS中輸入prop加兩次TAB會為我們生成AIP片斷):
這裡要注意一點,由於AIP的支持字段是編譯器自動生成的,而且編譯器每次編譯都可能更改這個名稱。所以在任何要序列化和反序列化的類型中,都不要使用AIP功能。
在實現編程中,我們經常構造一個對象,然後設置對象的一些公共屬性或字段。為此C#為我們提供了一種簡化的語法來完成這些操作。如下示例:
Name { ; Id { ; Age { ; Person p1 = = = = Person p2 = Person() { Id = , Name = , Age =
使用對象初始化器的語法時,實際上編譯器為我們生成的代碼和上面是一致的,但是下面的代碼明顯更加簡潔。如果本來就是要調用類型的無參構造器,C#還允許我們省略大括號之前的小括號:
Person p2 = Person { Id = , Name = , Age = };