前言
在不學 JAVA 換學 C# 之覺得心累 - L1:ch9 類別和物件 (一) 裡面介紹了類別和物件如何建立、this
代表的意義和用處、非靜態欄位和靜態欄位以及欄位的常數 const
和 readonly
等。
封裝與存取修飾詞
C# 提供多種存取修飾詞來控制類別成員的可見性 和存取範圍 。這是用來保護一些,不想或不用對外暴露的資料和演算法邏輯。
public
:在程式的任何地方 被存取。
private
:只能在同一個類別內 存取。命名規則為,建議在變數前加下底線 _
。
protected
:只能在同一個類別內或其子類別內 存取。
internal
:只能在同一個組件 (assembly) 內 存取。
封裝欄位 Field 與定義屬性 Property
通常實作上,我們會不希望欄位 (Field) 可以被直接修改,原因是:
封裝性 (Encapsulation):保護資料,不讓外部直接修改
當欄位是 public
,任何外部的程式碼都能直接修改它的值,這可能會導致錯誤或不安全的資料操作。
控制存取權限 (Read-Only / Write-Only 權限)
有些時候,我們希望欄位只能被讀取,不能被修改,或只能被內部設定,不能被外部改變。
可以額外執行邏輯 (如:記錄變更日誌、計算等)
易於維護,未來可以修改實作方式
早期,我們會希望透過 GetXXX
or SetXXX
方法來取得或修改資料,範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class Dog { private string _color; public string GetColor () { return _color; } public void SetColor (string color ) { this ._color = color; } } class Program { public static void Main () { Dog lucky = new Dog(); lucky.SetColor("white" ); string colorOfLucky = lucky.GetColor(); } }
屬性 Property 的 get
和 set
但是如果有很多欄位,而且大部分都沒有額外的邏輯,就會變成寫很多類似的程式碼,這樣很沒有效率,中期就演變出屬性 Property ,和欄位 Field 一樣名稱,差別僅開頭大小寫不同 ,然後可以這樣寫:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class Dog { private string _color; public string Color { get { return _color; } set { this ._color = value ; } } } class Program { public static void Main () { Dog lucky = new Dog(); lucky.Color = "black" ; string colorOfLucky = lucky.Color; } }
再一個範例
一間電影院裏面同時上映好幾部電影,想要紀錄電影的資料 title
, director
, Rating
和總共幾部電影 count
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 using System;namespace GetterSetter ;public class Movie { public string title; public string director; private string _rating; public static int count = 0 ; public Movie (string title, string director, string rating ) { this .title = title; this .director = director; this ._rating = rating; count++; } public string Rating { get { return _rating; } set { if (value == "G" || value == "PG" || value == "PG-13" || value == "R" || value == "NR" ) { _rating = value ; } else { _rating = "NR" ; } } } public int GetCount () { return count; } }
但是要寫的東西還是有點多,所以現在主要是使用自動實作屬性 (Automatically Implemented Properties) 。
自動實作屬性 (Automatically Implemented Properties)
是一種簡化屬性宣告的方式,讓你無需手動定義欄位 (Field) 來存取屬性背後的資料。
它是語法糖 的一種,語法糖是一種讓程式設計更加簡潔易讀的工具,不改變功能但是提升了可讀性與寫程式的效率。
語法
只需使用 get
和 set
存取器,不需要自訂邏輯 ,編譯器會自動生成隱藏的欄位。
1 2 3 4 5 public class Person { public string Name { get ; set ; } public int Age { get ; set ; } }
對比:
1 2 3 4 5 6 7 8 9 public string Name { get ; set ; } private string _name;public string Name{ get { return _name; } set { _name = value ; } }
優點
簡化程式碼:減少樣板程式碼 (boilerplate code)。
提高可讀性:讓程式碼更清晰易懂。
缺點
如果需要增加邏輯,就無法使用自動屬性,必須改用完整屬性宣告,例如:
1 2 3 4 5 6 private int _age;public int Age{ get { return _age; } set { if (value > 0 ) _age = value ; } }
參考資料:
自動實作的屬性 (C# 程式設計手冊)
物件初始化器 (Object Initializer)
物件初始化器 允許在建立物件時直接設定可存取的屬性值 (Property),無需建立很多不同的建構式,無須呼叫多個建構式或設定方法,從而簡化物件的初始化過程。但是物件初始化器還是基於建構式,若是相對應的建構式不對,會報錯。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class Person { public string Name { get ; set ; } public int Age { get ; set ; } public Person () {} } Person student = new Person(); student.Name = "Jenifer" ; student.Age = 10 ; Person student2 = new Person() { Name = "Jenifer" , Age = 10 }; Person student3 = new Person { Name = "Jenifer" , Age = 10 };
MS 的範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Cat { public int Age { get ; set ; } public string ? Name { get ; set ; } public Cat () {} public Cat (string name ) { this .Name = name; } } Cat cat1 = new Cat { Age = 10 , Name = "Fluffy" }; Cat cat2 = new Cat("Fluffy" ){ Age = 10 };
參考資料:
物件和集合初始設定式 (C# 程式設計手冊)
物件的陣列
先宣告一個物件陣列,宣告時即保留記憶體位址以便將來儲存 reference,並且都先初始化為 null
,但是還沒有實例化物件。利用 for
迴圈實例化物件。
以下的例子直接用上面 Person
類別:
1 2 3 4 5 Person[] people = new Person[5 ]; for (int i = 0 ; i < people.Length; i++){ people[i] = new Person { Name = "John" , Age = 100 }; }