DAY 14 類別(三)
類別
上次講的類別都屬於參考型別,今天會介紹實質型別的類別,如果忘記型別差異的話,可以回去看第二天的文章。
結構 struct
結構包含建構函式、常數、欄位、方法、屬性、索引子、運算子、事件和巢狀型別,不過如果需要數個這類成員,您應該考慮以類別來取代類型。
結構的用法與 class 相似,但結構使用時,無法初始化屬性,在下方用 class 示範如何初始化屬性
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
| class Program { static void Main (string[] args) { Member member = new Member (1, "Mio"); member.Print (); Memberc memberc = new Memberc (); memberc.Print (); } } struct Member { public Member (int id, string name) { ID = id; Name = name; } public int ID { get; } public string Name { get; } public void Print () { Console.WriteLine ($"ID: {id}, Name: {name}"); } } class Memberc { public Memberc () { } public Memberc (int id, string name) { ID = id; Name = name; } public int ID { get; } = 1; public string Name { get; } = "Mio"; public void Print () { Console.WriteLine ($"ID: {ID}, Name: {Name}"); } }
|
也就是當今天沒有傳入任何參數時,則會預設是 ID = 0, Name = Mio,隨便舉例而已。get 是存取子,還有一個是 set,如果只有 get 就是唯讀,只有 set 就是唯寫,詳細操作可以看下方連結。
結構往往是用在不可變的狀態下,像範例中的屬性成員是唯讀的,不能去修改。
列舉
包含一組稱為列舉程式清單之具名常數的不同類型
以資料庫連線狀態來舉例,假設連線狀態有未連接、嘗試連接與連接中三種狀態
如果不使用列舉,我們稱狀態為 0, 1, 2
1 2 3 4 5 6 7 8 9 10 11 12 13
| int connectionState;
switch (connectionState) { case 0: break; case 1: break; case 2: break; }
|
使用列舉後
1 2 3 4 5 6 7 8 9 10 11 12 13
| ConnectionState connectionState;
switch (connectionState) { case connectionState.Disconnected: break; case connectionState.Connecting: break; case connectionState.Connected: break; }
|
可讀性是不是差很多呢?兩者在運行時效能完全一樣,列舉的關鍵在於編譯時能宣告一組可以透過名稱來使用的整數值
1 2 3 4 5
| enum ConnectionState { Disconnected, Connecting, Connected }
|
在使用時,需要加入列舉名稱前綴如ConnectionState.Connected
,如果沒有任何預設值的話,列舉的數值從 0 開始排,也就是說
1 2 3 4 5 6 7 8 9 10 11
| static void Main (string[] args) { Console.WriteLine ($"Name = {MyEnum.A}, Value = {(int)MyEnum.A}"); Console.WriteLine ($"Name = {MyEnum.B}, Value = {(int)MyEnum.B}"); Console.WriteLine ($"Name = {MyEnum.C}, Value = {(int)MyEnum.C}"); Console.ReadKey (); } enum MyEnum { A, B, C }
|
但如果今天加入預設值後
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| static void Main (string[] args) { Console.WriteLine ($"Name = {MyEnum.A}, Value = {(int)MyEnum.A}"); Console.WriteLine ($"Name = {MyEnum.B}, Value = {(int)MyEnum.B}"); Console.WriteLine ($"Name = {MyEnum.C}, Value = {(int)MyEnum.C}"); Console.WriteLine ($"Name = {MyEnum.D}, Value = {(int)MyEnum.D}"); Console.WriteLine ($"Name = {MyEnum.E}, Value = {(int)MyEnum.E}"); Console.ReadKey (); } enum MyEnum { A, B = 8, C = 6, D, E }
|
可以自己玩玩看,列舉不是只有 int 而已,也可以宣告成 short 如
1 2 3 4 5 6 7
| enum MyEnum : short { A, B = 8, C = 6, D, E }
|
除了像是這種分開的狀態外,也會使用在可疊加狀態的,像是一個標誌來使用,以 System.IO.FileAttributes 舉例
1 2 3 4 5 6 7 8 9 10 11
| [Flags] public enum FileAttributes { ReadOnly = 1, Hidden = 2, System = 4, Directory = 8,
}
|
題外話:在設定初始值時,也可以像右邊的移位運算子(<<),會比較整齊。
這種列舉可以想成是二進位的加減,當你今天需要多重狀態時,就可以使用 OR 運算子來疊加,假設我今天需要前面兩種狀態的話,如
1 2 3 4 5
| static void Main (string[] args) { System.IO.FileAttributes FA = System.IO.FileAttributes.Hidden | System.IO.FileAttributes.ReadOnly; Console.WriteLine ($"Name = {FA}, Value = {(int)FA}"); Console.ReadKey (); }
|
可以看到名稱很完整的印出了每個狀態,因為在使用這個列舉時有加一個 Attribute(屬性) [Flags]
,可以自己撰寫一個以二進位方式的列舉,加入這個屬性來看差異。
題外話:雖然中文都翻屬性,但我覺得有時候講起來很容易混淆,不知道有沒有路過的大大可以提通我更好的中文字詞。
一些小結論
今天把實質型別的類別做了個大概,本來在實務上是很少使用結構的,都是使用 class 類別來取代,所以在說類別時,往往就是指 class 了。而列舉就比較容易遇到,因為可以讓程式碼在讀的時候比較好懂。
感謝閱讀。
參考連結
struct (C# 參考) | Microsoft Docs
get (C# 參考) | Microsoft Docs
enum 關鍵字 (C# 參考) | Microsoft Docs