一、 關於 類型
再具體學習枚舉類型之前,先瞭解一下C#的類型。
(1)實值型別
(a)變數可以直接包含它們自己的資料;如 int i = 35;
(b)局部變數總是放在棧(stack)中。
· (2)參考型別
(a)變數間接指向它們的資料;
(b)局部變數指向堆(heap)中的對象.
枚舉(enum) 實值型別
結構(struct) 實值型別
類(class) 參考型別
介面(interface) 參考型別
數組([ ]array ) 參考型別
委託(delegate) 參考型別
關於兩者的區別可以參考文章:C#參考 : 實值型別和參考型別的區別 (深入詳解)
也許,你對上面的例子感到一點點奇怪,c#中的那些內在類型如int,double怎麼沒有。這是因為:C#規定這些內在類屬於結構,C#稱之為簡單類型。簡單類型和使用者自訂類型之間的最大區別是前者可以有字面運算式(如42),而後者沒有。
當然,還有第三種類型:指標。但指標只用在由unsafe關鍵字標識的非安全的代碼中。
二、枚舉類型
它是一個使用者聲明的實值型別
enum Suit
{
Clubs,
Diamonds,
Hearts,
Spades
}
//Suit表示一副牌,它有4個花色:梅花(Clubs),方塊(Diamonds),紅心(Hearts),//黑桃(Spades)
sealed class Example
{
static void Main()
{
Suit lead = Spades; //錯誤
Suit trumps = Suit.Clubs; //正確
}
}
枚舉的聲明可以出現在類聲明的相同地方。
枚舉的聲明包括名字、存取權限、內在的類型和枚舉的成員。
枚舉中聲明的常量的範圍是定義它們的枚舉,換言之,下面的例子是錯誤的:
Suit trumps = Clubs;
Clubs必須被限制為Suit的一個成員,就如下面:
Suit trumps = Suit.Clubs;
三、枚舉的注意點
· 枚舉值預設為int; 你可以選擇任一內在的整數類型,但不可以是字元類型.
enum Suit : int //內在類型是int,可以省略
{
Clubs,
Diamonds,
Hearts = 42, //成員的取值預設為前一個成員取值+1,但可以自己賦初值
Spades, //最後一個分號是可選的
};//可以有結尾分號
1). 枚舉類可以顯式的聲明它的內在類型是sbyte, byte, short, ushort, int, uint, long, ulong。如果一個枚舉類沒有顯式聲明它的內在類型,則預設為int。
2). 成員的取值必須和枚舉聲明的內在類型相同,並且必須在內在類型的範圍之內(例如,你不能讓成員的取值為負數,而枚舉的內在類型準確的說是uint)。
3). 如果成員沒有被賦值, 那麼它的取值是前一個成員取值+1,第一個成員的預設值是1。枚舉的成員的取值可以有相同的取值。
4). 最後一個枚舉成員可以使用一個結尾分號,這使得你將來可以很方便地加入更多的成員。
5). 枚舉成員的存取權限隱含為public。
四、枚舉類型應用詳解
(1)優先考慮使用枚舉,而不是類的靜態常量。
比如:
public static class Day
{
public static int Sun = 1;
public static int Mon = 2;
public static int Tue = 3;
//
}
應該使用如下的枚舉:
enum Day
{
Sun = 1,
Mon,
Tue,
Wed,
Thu,
Fri,
Sat
};
(2)如果參數、傳回值、變數等類型可以是枚舉,則不要使用其它基礎類型。
比如:Range r = Range.MAX; //好
int r = (int)Range.MAX; //不好
(3)枚舉命名
枚舉一般使用名詞或名片語合,簡單枚舉使用單數,標誌枚舉使用複數。
(4)大多數情況下不需要更改枚舉的預設類型
也就是說大多數情況下,使用 int(System.Int32)作為枚舉類型。除非:
- 枚舉是標誌枚舉,且標誌多於 32 個(此時 int 類型裝不下)。
- 枚舉被非常大量且頻繁地使用,為了節約空間使用小於 int 的類型。
- 不得不使用其它類型的情況。
(5)不要在枚舉中設定“哨兵”
我們可能覺得在枚舉的兩端加上哨兵,這樣在判斷一個數是否在枚舉中時,只需要判斷是否在哨兵之中。非常不幸,我們不應該這麼做,這破壞了枚舉的意義。
enum Day {FirstValue, Sun, Mon, Tue, Wed, Thu, Fri, Sat, LastValue }; //FirstValue、LastValue 應該去掉
- 簡單枚舉包含的值不用於組合,也不用於位元壓縮。
- 標誌枚舉應使用按位 OR 操作進行組合。
(6)簡單枚舉
前面提到的 Day、Range 都可以稱之為簡單枚舉,因為不能將他們各自的值組合起來。
(7)標誌枚舉
標誌枚舉的設計有兩點要注意。
- 指明 FlagsAttribute,以指示可以將枚舉作為位域(即一組標誌)處理。
- 枚舉中各標誌的值應該是以 2 的冪來賦值,即:1、2、4、8、16、32……
舉個例子,假如我們在設計 Windows 視窗程序,視窗有最小化、最大化、關閉按鈕,我們想任意組合顯示,也就是說我們可以顯示其中的任意 0 個或一個或多個按鈕。
如果使用簡單枚舉,按照排列組合,就存在8中情況,那麼要使用8個枚舉數,如果這裡不是三個按鈕,而是四個按鈕,枚舉數就更多了。所以這樣不現實。
為什麼這裡使用簡單枚舉不現實呢?因為簡單枚舉不能組合,採用標誌枚舉就可以輕鬆解決了。
[Flags]
public enum WindowStyle
{
MINIMUM_BUTTON = 1, //十六進位表示為 0x0001
MAXIMUM_BUTTON = 2,
CLOSE_BUTTON = 4
}
我們在設定視窗樣式時,利用 'OR' 自由組合:
WindowStyle ws = WindowStyle.MINIMUM_BUTTON | WindowStyle.CLOSE_BUTTON;
//表示既有 MINIMUM_BUTTON 也有 CLOSE_BUTTON
這就是為什麼標誌的值要按 2 的冪排列的原因了,也是為什麼標誌多於 32 個時不能使用 int 類型的原因了。
通常我們為常用的標誌組合提供特殊的枚舉值
仍然以上述視窗為例,可知大多數情況下,我們均要顯示這三個按鈕,所以每次使用時都要用:
WindowStyle ws = WindowStyle.MINIMUM_BUTTON | MAXIMUM_BUTTON | WindowStyle.CLOSE_BUTTON;
實在有些繁瑣,我們可以修改枚舉為如下:
[Flags]
public enum WindowStyle
{
MINIMUM_BUTTON = 1,
MAXIMUM_BUTTON = 2,
CLOSE_BUTTON = 4,
ALL_BUTTON = 7
}
增加一個 ALL_BUTTON 為前三個標誌的值。使用時直接用 ALL_BUTTON 就可以了。