19 列舉
19.1 一般
列舉類型是宣告一組具名常數的相異實值型別 (~8.3)。
範例: 範例
enum Color { Red, Green, Blue }
宣告名為
Color
且成員Red
、Green
和Blue
的列舉型別。end 範例
19.2 列舉宣告
列舉宣告會宣告新的列舉類型。 列舉宣告的開頭為 關鍵詞 enum
,並定義列舉的名稱、輔助功能、基礎類型和成員。
enum_declaration
: attributes? enum_modifier* 'enum' identifier enum_base? enum_body ';'?
;
enum_base
: ':' integral_type
| ':' integral_type_name
;
integral_type_name
: type_name // Shall resolve to an integral type other than char
;
enum_body
: '{' enum_member_declarations? '}'
| '{' enum_member_declarations ',' '}'
;
每個列舉類型都有一個對應的整數類型, 稱為列舉型別的基礎類型 。 這個基礎類型應該能夠代表列舉中定義的所有列舉值。 如果enum_base存在,它會明確宣告基礎類型。 基礎型別必須是 以外的其中一個整數型別(~8.3.6)。char
基礎型別可由 integral_type
(~8.3.5) 或 integral_type_name
指定。 的 integral_type_name
解析方式與 type_name
(~7.8.1) 相同,包括將任何 using 指示詞 (~14.5) 納入考慮。
注意:型
char
別不能做為基礎型別,可以透過 關鍵詞或 透過integral_type_name
。 end note
未明確宣告基礎型別的列舉宣告,其基礎型別 int
為 。
範例:範例
enum Color : long { Red, Green, Blue }
宣告具有基礎型別的
long
列舉。end 範例
注意:開發人員可能會選擇使用 的基礎型
long
別,如範例所示,啟用在範圍中,但不int
在範圍中的值long
使用,或保留這個選項供未來使用。 end note
注意:C# 允許enum_body中的尾端逗號,就像它允許array_initializer中的逗號一樣(~17.7)。 end note
列舉宣告不能包含類型參數清單,但是泛型類別宣告或泛型結構宣告內巢狀的任何列舉都是泛型列舉宣告,因為應該提供包含型別的型別自變數來建立建構型別 ({8.4)。
19.3 列舉修飾詞
enum_declaration可以選擇性地包含列舉修飾詞序列:
enum_modifier
: 'new'
| 'public'
| 'protected'
| 'internal'
| 'private'
;
同一個修飾詞在列舉宣告中出現多次是編譯時期錯誤。
列舉宣告的修飾詞與類別宣告的修飾詞意義相同({15.2.2)。 不過, abstract
列舉宣告中不允許 、 和 sealed
和 static
修飾詞。 列舉不可以是抽象的,而且不允許衍生。
19.4 列舉成員
列舉類型宣告的主體會定義零個或多個列舉成員,也就是列舉類型的具名常數。 沒有兩個列舉成員可以有相同的名稱。
enum_member_declarations
: enum_member_declaration (',' enum_member_declaration)*
;
enum_member_declaration
: attributes? identifier ('=' constant_expression)?
;
每個列舉成員都有相關聯的常數值。 這個值的類型是包含列舉的基礎類型。 每個列舉成員的常數值應位於列舉的基礎類型範圍內。
範例:範例
enum Color: uint { Red = -1, Green = -2, Blue = -3 }
會產生編譯時間錯誤,因為 常數值
-1
、-2
和-3
不在基礎整數型uint
別的範圍內。end 範例
多個列舉成員可以共用相同的相關聯值。
範例:範例
enum Color { Red, Green, Blue, Max = Blue }
顯示列舉,其中兩個列舉成員
Blue
和Max
— 具有相同的關聯值。end 範例
列舉成員的相關值會以隱含或明確方式指派。 如果列舉成員的宣告具有 constant_expression 初始化表達式,則該常數表達式的值會隱含轉換成列舉的基礎類型,是列舉成員的關聯值。 如果列舉成員的宣告沒有初始化表達式,則會隱含地設定其相關聯的值,如下所示:
- 如果列舉成員是列舉類型中宣告的第一個列舉成員,則其相關聯的值為零。
- 否則,會藉由將前面列舉成員的關聯值增加一個,以取得列舉成員的關聯值。 這個增加的值應該在基礎類型可以表示的值範圍內,否則會發生編譯時期錯誤。
範例:範例
enum Color { Red, Green = 10, Blue } class Test { static void Main() { Console.WriteLine(StringFromColor(Color.Red)); Console.WriteLine(StringFromColor(Color.Green)); Console.WriteLine(StringFromColor(Color.Blue)); } static string StringFromColor(Color c) { switch (c) { case Color.Red: return $"Red = {(int) c}"; case Color.Green: return $"Green = {(int) c}"; case Color.Blue: return $"Blue = {(int) c}"; default: return "Invalid color"; } } }
會列印列舉成員名稱及其相關聯的值。 輸出如下:
Red = 0 Green = 10 Blue = 11
基於下列原因:
- 列舉成員
Red
會自動指派零值(因為它沒有初始化表達式,而且是第一個列舉成員):- 列舉成員
Green
明確指定值10
;- 和列舉成員
Blue
會自動指派大於文字前面之成員的值。end 範例
列舉成員的關聯值不得直接或間接使用其本身相關聯列舉成員的值。 除了這個迴圈限制之外,列舉成員初始化表達式可以自由參考其他列舉成員初始化表達式,而不論其文字位置為何。 在列舉成員初始化表達式內,其他列舉成員的值一律會被視為具有其基礎類型的類型,因此參考其他列舉成員時不需要轉換。
範例:範例
enum Circular { A = B, B }
會導致編譯時期錯誤,因為和
B
的A
宣告是迴圈的。A
相B
依於明確,並B
隱含相依A
。end 範例
列舉成員是以與類別內欄位完全相同的方式命名和範圍。 列舉成員的範圍是其包含列舉類型的主體。 在該範圍內,列舉成員可以透過其簡單名稱來參考。 從所有其他程式代碼中,列舉成員的名稱應以其列舉類型的名稱限定。 列舉成員沒有任何宣告的存取範圍,如果列舉成員包含列舉類型可供存取,則為可存取。
19.5 System.Enum 類型
此類型 System.Enum
是所有列舉類型的抽象基類(這與列舉型別的基礎類型不同),繼承自 System.Enum
的成員可在任何列舉類型中使用。 從任何列舉類型到 的 Boxing 轉換 (~10.2.9)存在,而且從 到任何列舉類型都存在 System.Enum
Unboxing 轉換 (~10.3.7)。System.Enum
請注意, System.Enum
本身不是 enum_type。 相反地,這是衍生所有enum_type的class_type。 型 System.Enum
別繼承自 類型 System.ValueType
(~8.3.2),接著繼承自 類型 object
。 在運行時間,型 System.Enum
別的值可以是 null
或任何列舉型別之 Boxed 值的參考。
19.6 列舉值和作業
每個列舉類型都會定義不同的類型;在列舉型別與整數型別之間或兩個列舉型別之間轉換,必須有明確的列舉轉換(~10.3.3)。 列舉類型的值集合與基礎類型的值集相同,而且不限於具名常數的值。 列舉之基礎類型的任何值都可以轉換成列舉類型,而且是該列舉類型的相異有效值。
列舉成員具有其包含列舉類型的類型(但在其他列舉成員初始化運算式內除外:請參閱 \19.4)。 在具有相關聯值的列舉類型 E
中宣告的列舉成員值為 v
(E)v
。
下列運算子可用於列舉類型的值:
==
、!=
、<
、>
、<=
、>=
、(~12.12.6)- binary
+
(~12.10.5) - binary
-
(~12.10.6) ^
、、&
|
(~12.13.3)~
(~12.9.5)++
、--
(~12.8.15 和 *12.9.6)sizeof
(*23.6.9)
每個列舉類型都會自動衍生自 類別 System.Enum
(接著衍生自 System.ValueType
和 object
)。 因此,這個類別的繼承方法和屬性可用於列舉類型的值。