列舉型別(或enum型別)是一種由基礎整數型別的一組具名常數所定義的值型別。 若要定義列舉型別,請使用 enum 關鍵詞並指定 列舉成員的名稱:
enum Season
{
Spring,
Summer,
Autumn,
Winter
}
預設情況下,列舉成員的相關常數值為型別 int。 它們從零開始,依照定義文字順序增加一。 您可以明確地將任何其他 整數數值 類型指定為列舉型別的基礎類型。 您也可以明確指定相關聯的常數值,如下列範例所示:
enum ErrorCode : ushort
{
None = 0,
Unknown = 1,
ConnectionLost = 100,
OutlierReading = 200
}
你無法在列舉型別的定義中定義方法。 若要為列舉型別新增功能,請建立 擴充成員。
列舉型別 E 的預設值是由表達式 (E)0 所產生的值,即便零沒有對應的列舉成員。
從零隱含轉換
C# 允許從常值 0 隱含轉換成任何列舉類型,以及從 const 等於零的值進行隱含轉換。 當列舉不包含值為零的成員時,此行為可能會導致非預期的結果:
public enum GpioPort
{
GpioA = 1,
GpioB,
GpioC,
GpioD
}
public class ZeroConversionExample
{
public static void Main()
{
// This compiles without warning but creates an invalid enum value
GpioPort port1 = (GpioPort)0;
Console.WriteLine($"port1: {port1}"); // Output: port1: 0
// This also compiles due to implicit conversion from zero
GpioPort port2 = GetPort(0);
Console.WriteLine($"port2: {port2}"); // Output: port2: 0
// Check if the enum value is valid
bool isValid1 = Enum.IsDefined(typeof(GpioPort), port1);
bool isValid2 = Enum.IsDefined(typeof(GpioPort), port2);
Console.WriteLine($"port1 is valid: {isValid1}"); // Output: port1 is valid: False
Console.WriteLine($"port2 is valid: {isValid2}"); // Output: port2 is valid: False
// Safer approach - validate enum values
if (Enum.IsDefined(typeof(GpioPort), 0))
{
GpioPort safePort = (GpioPort)0;
}
else
{
Console.WriteLine("Value 0 is not a valid GpioPort");
// Handle the invalid case appropriately
}
}
public static GpioPort GetPort(GpioPort port)
{
return port;
}
}
在上述範例中,和 port1 都會port2指派 值0,但沒有GpioPort具有該值的成員。
Enum.IsDefined方法會確認這些列舉值無效。
這種隱含轉換存在,是因為 0 位元模式是所有結構型態的預設值,包括所有枚舉型別。 不過,它可以在您的程式代碼中引入 Bug。 為了避免這些問題:
- 幾乎總是要在你的列舉中定義有價值
0的成員。 - 從數值類型轉換時,使用 Enum.IsDefined 來驗證列舉值。
- 使用可能隱含轉換成列舉類型的數值參數時,請小心謹慎。
使用列舉型別來表示一組互斥值中的選擇,或是多個選項的組合。 若要表示選擇的組合,請將列舉型別定義為位旗標。
列舉型別作為位元標誌
如果你想讓列舉類型代表多個選擇的組合,請為這些選擇定義枚舉成員,使得每個選擇都是一個位元欄位。 也就是說,將這些枚舉成員的相關值視為二的冪次方。 接著,使用 位元邏輯運算子 | 或 & 分別組合選項或交集選項組合。 若要指出列舉類型宣告位元欄,請將 Flags 屬性套用至它。 如下列範例所示,您也可以在列舉型別的定義中包含一些典型的組合。
[Flags]
public enum Days
{
None = 0b_0000_0000, // 0
Monday = 0b_0000_0001, // 1
Tuesday = 0b_0000_0010, // 2
Wednesday = 0b_0000_0100, // 4
Thursday = 0b_0000_1000, // 8
Friday = 0b_0001_0000, // 16
Saturday = 0b_0010_0000, // 32
Sunday = 0b_0100_0000, // 64
Weekend = Saturday | Sunday
}
public class FlagsEnumExample
{
public static void Main()
{
Days meetingDays = Days.Monday | Days.Wednesday | Days.Friday;
Console.WriteLine(meetingDays);
// Output:
// Monday, Wednesday, Friday
Days workingFromHomeDays = Days.Thursday | Days.Friday;
Console.WriteLine($"Join a meeting by phone on {meetingDays & workingFromHomeDays}");
// Output:
// Join a meeting by phone on Friday
bool isMeetingOnTuesday = (meetingDays & Days.Tuesday) == Days.Tuesday;
Console.WriteLine($"Is there a meeting on Tuesday: {isMeetingOnTuesday}");
// Output:
// Is there a meeting on Tuesday: False
var a = (Days)37;
Console.WriteLine(a);
// Output:
// Monday, Wednesday, Saturday
}
}
如需詳細資訊和範例,請參閱 System.FlagsAttribute API 參考頁面和 非獨佔成員和 API 參考頁面的 System.Enum Flags 屬性一節。
System.Enum 類型和列舉條件約束
此 System.Enum 類型是所有列舉型別的抽象基類。 它提供了多種方法來取得關於列舉類型及其值的資訊。 如需詳細資訊和範例,請參閱 System.Enum API 參考頁面。
您可以在 System.Enum 基類條件 約束中使用 ,以指定類型參數是列舉型別。 任何列舉型別也都滿足 struct 條件約束,用來指定類型參數是不可為 Null 的實值型別。
轉換次數
對於任何列舉類型,列舉類型與其底層整數類型之間存在明確的轉換。 如果您將列舉值 轉換成 其基礎類型,結果就是列舉成員的相關聯整數值。
public enum Season
{
Spring,
Summer,
Autumn,
Winter
}
public class EnumConversionExample
{
public static void Main()
{
Season a = Season.Autumn;
Console.WriteLine($"Integral value of {a} is {(int)a}"); // output: Integral value of Autumn is 2
var b = (Season)1;
Console.WriteLine(b); // output: Summer
var c = (Season)4;
Console.WriteLine(c); // output: 4
}
}
使用此 Enum.IsDefined 方法判斷列舉類型是否包含具有特定相關值的列舉成員。
對於任何列舉類型,分別存在與該類型的箱盒轉換與開System.Enum箱轉換。
C# 語言規格
如需詳細資訊,請參閱 C# 語言規格的下列幾節: