程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#基礎之類型和成員基礎以及常量、字段、屬性

C#基礎之類型和成員基礎以及常量、字段、屬性

編輯:C#入門知識

首先吐糟一下今天杭州的天氣,真是太熱了!雖然沒有妹子跟我約會,但宅在方寸大的窩裡,也是煩躁不已!

接上一篇《C#基礎之基本類型》

類型和成員基礎

在C#中,一個類型內部可以定義多種成員:常量、字段、實例構造器、類型構造器(靜態構造器)、方法、操作符重載、轉換操作符、屬性、事件、類型。

類型的可見性publicinternal(默認)兩種,前者定義的類型對所有程序集中的所有類型都可見,後者定義的類型只對同一程序集內部的所有類型可見:

   PublicClass { }                
   ExplicitlyInternalClass { }  
  ImplicitlyInternalClass { }           

成員的可訪問性(按限制從大到小排列):

  • Private只能由定義成員的類型或嵌套類型中方法訪問
  • Protected只能由定義成員的類型或嵌套類型或派生類型中方法訪問
  • Internal 只能由同程序集類型中方法訪問
  • Protected Internal 只能由定義成員的類型或嵌套類型或派生類型或同程序集類型中方法訪問(注意這裡是或的關系)
  • Public 可由任何程序集中任何類型中方法訪問

在C#中,如果沒有顯式聲明成員的可訪問性,編譯器通常默認選擇Private(限制最大的那個),CLR要求接口類型的所有成員都是Public訪問性,C#編譯器知道這一點,因此禁止顯式指定接口成員的可訪問性。同時C#還要求在繼承過程中派生類重寫成員時,不能更改成員的可訪問性(CLR並沒有作這個要求,CLR允許重寫成員時放寬限制)。

靜態類

永遠不需要實例化的類,靜態類中只能有靜態成員。在C#中用static這個關鍵詞定義一個靜態類,但只能應用於class,不能應用於struct,因為CLR總是允許值類型實例化。

C#編譯器對靜態類作了如下限制:

  • 靜態類必須直接從System.Object派生
  • 靜態類不能實現任何接口(因為只有使用類的一個實例才能調用類的接口方法)
  • 靜態類只能定義靜態成員(字段、方法、屬性、事件)
  • 靜態類不能作為字段、方法參數或局部變量使用
  • 靜態類在編譯後,會生成一個被標記為abstract和sealed的類,同時編譯器不會生成實例構造器(.ctor方法)

分部類、結構和接口

C#編譯器提供一個partial關鍵字,以允許將一個類、結構或接口定義在多個文件裡。

在編譯時,編譯器自動將類、結構或接口的各部分合並起來。這僅是C#編譯器提供的一個功能,CLR對此一無所知。

常量

常量就是代表一恆定數據值的符號,比如我們將圓周率3.12415926定義成名為PI的常量,使代碼更容易閱讀。而且常量是在編譯時就代入運算的(常量就是一個符號,編譯時編譯器就會將該符號替換成實際值),不會造成任何性能上的損失。但這一點也可能會造成一個版本問題,即假如未來修改了常量所代表的值,那麼用到此常量的地方都要重新編譯(我個人認為這也是常量名稱的由來,我們應該將恆定不變的值定義為常量,以免後期改動時產生版本問題)。下面的示例也驗證了這一點,Test1和Test2方法內部的常量運算在編譯後,就已經運算完成。

從上面示例,我們還能看出一點:常量key和value編譯後是靜態成員,這是因為常量通常與類型關聯而不是與實例關聯,從邏輯上說,常量始終是靜態成員。但對於在方法內部定義的常量,由於作用域的限制,不可能有方法之外的地方引用到這個常量,所以在編譯後,常量被優化了。

字段

字段是一種數據成員,在OOP的設計中,字段通常是用來封裝一個類型的內部狀態,而方法表示的是對這些狀態的一些操作。

在C#中字段可用的修飾符有

  • Static 聲明的字段與類型關聯,而不是與對象關聯(默認情況下字段與對象關聯)
  • Readonly 聲明的字段只能在構造器裡寫入值(可以通過反射修改)
  • Volatile 聲明的字段為易失字段(用於多線程環境)

這裡要注意的是將一個字段標記為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 =  };
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved