C#對象和類型——C#進階編程第三章

來源:互聯網
上載者:User

  本節內容:類和結構的區別、類成員、按值和按引用傳送參數、方法重載、建構函式和靜態建構函式、唯讀欄位、部分類、靜態類、Object類(基類)。

一、類和結構

類用class修飾,結構用struct修飾。如:

 1 class PhoneCustomer
2 {
3 public const string DayOfSendingBill="Monday";
4 public int CustomerID;
5 public string FirstName;
6 public string LastName;
7 }
8
9 struct PhoneCustomerStruct
10 {
11 public const string DayOfSendingBill="Monday";
12 public int CustomerID;
13 public string FirstName;
14 public string LastName;
15 }

  結構和類的區別是它們在記憶體中的儲存方式、訪問方式(類是儲存在堆上的參考型別,而結構是儲存在棧上的實值型別)和它們的一些特徵(如結構不支援繼承)。較小的資料類型使用結構可以提高效能。在文法上,兩者十分相似。對於類和結構都使用new來聲明執行個體:這個關鍵字建立對象並對其進行初使化。

二、類:類中的資料和函數稱為類的成員

1.資料成員:是包含類的資料——欄位、常量、事件的成員,資料成員可以是待用資料,類成員總是執行個體成員,除非用static進行顯示聲明。一旦執行個體化PhoncCustomer對象,就可以使用文法Object.FieldName來訪問這些欄位,如下:

1 PhoneCustomer Customer = new PhoneCustomer();
2 Customer.FirstName="Simon";

2.函數成員:提供了操作類中資料的某些功能,包括方法、屬性、建構函式和終結器(finalizer)、運算子以及索引器。

  給方法傳遞參數可以通過引用或值傳遞給方法,在通過引用傳遞(ref,out)時,被調用的方法得到的就是這個變數,所以在方法內部對變數進行的任何改變在方法退出後仍舊有效,而如果變數通過值傳遞給方法,被調用的方法得到的是變數的一個相同副本,在方法退出後,對變數進行的任何修改會丟失。對於複雜的資料類型,按引用傳遞效率更高,因為按值傳遞時必須複製大量的副本。在C#中,除非特殊說明,所有的參數都是通過值來傳遞。請看下面的例子:

 1 public static int Main() 
2 {
3 int i = 0;
4 int[] ints = {0,1,2,4,8};
5 Console.WriteLine("i = " + i);
6 Console.WriteLine("ints[0] = " + ints[0]);
7 Console.WriteLine("Calling SomeFunction...");
8 someFunction(ints, i);
9 Console.WriteLine("i = " + i);
10 Console.WriteLine("ints[0] = " + ints[0]);
11 return 0;
12 }
13
14 static void someFunction(int[] ints,int i)
15 {
16 ints[0] = 100;
17 i=100;
18 }

輸出結果為:

i=0
ints[0]=0
Calling SomeFunction...
i=0
ints[0]=100

注意,i的值保持不變,而在ints中改變的值在原始數組中也改變了!string雖然是參考型別,但是在傳遞時,對字串的任何改變不會影響原始字串。

如果想讓方法體內的改變影響到方法外,用ref或out關鍵字修飾即可。

具名引數:一般參數需要按定義的順序傳送給方法,而具名引數允許按任意順序傳遞。如:

 string FullName(string firstName,string lastName)
{
return firstName+""+lastName;
}
下面的調用會返回相同的全名:
FullName("Join","Doe");
FullName(lastName:"Doe",firstName:"Join");

選擇性參數:必須為選擇性參數提供預設值,選擇性參數必須是方法定義的最後一個參數。

方法的重載:C#支援方法重載——方法的多個版本有不同的簽名(方法名相同,但參數個數或類型不同)。但是2個方法不能僅在傳回型別上有區別,也不能根據參數聲明為ref和out來區分。

屬性:它是一個方法或一對方法,在用戶端代碼看來,它是一個欄位,如Windows的Height屬性:mainForm.Height=400;屬性有唯讀唯寫屬性、自動屬性(不能嚴重有效性,必須為可讀寫屬性)。

3.建構函式:一個與類同名沒有傳回值的方法。如果不顯示聲明,系統會自動建立一個預設建構函式。一旦顯示聲明建構函式,編譯器就不會提供預設的建構函式。

  C#的一個特性是可以給類編寫一個無參的靜態建構函式,這個函數只執行一次,而執行個體建構函式,只要類建立對象就會執行。編寫靜態建構函式的一個原因是:類的某些靜態欄位和屬性,需要在第一次使用類之前,從外部源中初始化這些欄位和屬性。

  建構函式初始化器:實現從建構函式調用其他建構函式,建構函式初始化器在建構函式的函數體之前執行,用this關鍵字修飾,如下:

 1 class Car
2 {
3 private string description;
4 private int nWheels;
5 public Car(string description,int nWheels)
6 {
7 this.description=description;
8 this.nWheels=nWheels;
9 }
10
11 public Car(string description):this(description,4)
12 {
13
14 }
15 }

在執行Car myCar=new Car("proton persona")時,會先執行帶2個參數的建構函式,C#建構函式初始化器可以包含對同一個類的另一個建構函式的調用,也可以包含對直接基類的建構函式的調用,使用base關鍵字代替this。初始化器不能有多個調用。

  唯讀欄位:類似常量,用readonly關鍵字修飾,比常量(const修飾)靈活的多,唯讀欄位在運行前其值是未知的,只能在建構函式中給唯讀欄位賦值,類的不同執行個體唯讀欄位的值可以不同(執行個體唯讀欄位),也可以是靜態。如果有一個用於編輯文檔的MDI程式,因為需要註冊,所以要限制可以同時開啟的文檔數,顯然不能在原始碼中對最大數目進行寫入程式碼,而是需要一個欄位表示,這時就要使用唯讀欄位。注意如果在建構函式中沒有給唯讀欄位賦值,它將是特定資料類型的預設值。

三、匿名型別:var關鍵字與new關鍵字一起使用時,可以建立匿名型別,匿名型別是一個繼承自object且沒有名稱的類,該類的定義從初始化器中推斷,類似隱式類型化的變數,如:

var caption = new {FirstName="James",MiddleName="T",LastName="Kirk"};

就會產生一個包含三個屬性的對象。如果在建立一個類似的對象doctor,就可以設定caption=doctor。如果doctor的值來自於caption,可以簡化初始化器,如下:

var doctor=new {caption.FirstName,caption.MiddleName,caption.LastName};

這些新對象的類型名未知,編譯器為類型‘偽造’了一個名稱,只有編譯器才能使用它,我們不能使用新對象的任何類型反射。

四、結構:在需要一個小的資料結構時,類提供的功能多於我們需要的功能,由於效能原因,這時最後使用結構。

  結構是實值型別,他們儲存在棧中或儲存為內聯(inline),結構不支援繼承,編譯器總是為結構提供一個無參的預設建構函式,它是不允許替換的,使用結構可以指定欄位如何在記憶體中的布局。

  為結構建立執行個體時不需要使用new關鍵字,直接聲明即可。注意在結構類型作為參數傳遞的時候,對結構賦值,結構的所有內容都被複製,而不是複製其引用,這時需要使用ref修飾,以免效能損失。

五、部分類:partial關鍵字允許把類、結構或介面放在多個檔案中。在多個開發人員需要訪問同一個類,或者某種類型的代碼產生器產生了一個類的某部分,把類放在多個檔案中是有意義的。在巢狀型別中,只要partial關鍵字在class關鍵字前面,就可以嵌套部分類,在把部分類編譯到類型中時,屬性、介面、泛型的參數屬性和成員都會合并。

六、靜態類:如果類只包含靜態方法和屬性,該類就是靜態,不能建立靜態類的執行個體,靜態類中的靜態方法調用時只能通過類名調用。

七、Object類:所有.net類的基類,如果定義一個類的時候沒有指定基類,編譯器就會自動假設這個類派生自Object。所有類都可以調用Object定義的許多公有和受保護的成員方法。如:ToString(),GetHashTable(),Equals()和ReferenceEquals(),Finalize(),GetType(),MemberwiseClone()等方法。

八、擴充方法:在沒有原始碼時擴充類的功能時使用擴充方法。擴充方法是靜態方法,它是類的一部分,但實際上沒有放到該類的原始碼中。如為Money類增加一個方法AddToAmount(decimal amountToAdd):

1 public static class MoneyExtension
2 {
3 public static void AddToAmount(this Money money,decimal amountToAdd)
4 {
5 money.Amount+=amountToAdd;
6 }
7 }

  對於擴充方法,第一個參數是要擴充的類型,放在this關鍵字後面,告訴編譯器這個方法是Money類的一部分。在擴充方法中可以訪問所擴充類的所有公有方法和屬性。在主程式中,
AddToAmount方法看起來像是另一個方法,沒有顯示第一個參數,也不能對其做任何處理,調用時與其他方法相同:cash.AddToAmount(10m);,雖然擴充方法是靜態,但在調用時也要用標準的執行個體方法文法。如果類中存在與擴充方法同名的方法,此時調用時不會調用擴充方法。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.