列舉型別(或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使用方法來判斷列舉類型是否包含具有特定關聯值的列舉成員。
對於任何列舉型別,分別有 Boxing 和 unboxing 轉換到 型別和從 System.Enum 類型轉換。
C# 語言規格
如需詳細資訊,請參閱 C# 語言規格的下列幾節: