小提示
剛開始開發軟體嗎? 先從 入門 教學開始。 當你需要在程式碼中表示一組固定的選擇時,就會遇到列舉型別。
有其他語言的經驗嗎? C# 枚舉的運作方式類似 Java 或 C++ 中的枚舉,並額外支援位元旗標與模式匹配。 瀏覽 旗標 和 switch 表達式 區段,以尋找 C# 特定的模式。
列 舉型別 (或列 舉)定義了一組以整數值為後盾的命名常數。 當值必須是固定選項之一時,例如星期幾、HTTP 狀態碼、日誌等級或方向,則使用枚舉。 枚舉讓你的程式碼更易讀,也比原始整數常數更不容易出錯,因為編譯器會強制執行指定的值。
宣告一個枚舉
使用 enum 關鍵字來定義列舉,其後緊跟著型別名稱及其成員:
enum Season
{
Spring,
Summer,
Autumn,
Winter
}
預設底層型別為 int,值從 開始 0 ,遞增一。
Season.Spring 是 0、 Season.Summer 是 1、 ,依此類推。
指定底層型別及明確值
你可以選擇不同的積分類型,並指定明確的數值來控制數值表示:
enum HttpStatus : ushort
{
OK = 200,
NotFound = 404,
InternalServerError = 500
}
當數字具有外部意義,例如HTTP狀態碼或協定識別碼時,請使用明確的值。 底層型態可以是任何整數型別,唯獨char除外。 使用byte、short、ushort、intuintlong或。ulong
在交換表達式中使用枚舉
枚舉自然地與 switch 表達式和模式匹配合作。 若未處理所有成員,編譯器會警告你,這有助於在之後新增值時避免錯誤。
static string DescribeSeason(Season season) => season switch
{
Season.Spring => "Flowers bloom and temperatures rise.",
Season.Summer => "Long days and warm weather.",
Season.Autumn => "Leaves change color and fall.",
Season.Winter => "Short days and cold temperatures.",
_ => throw new ArgumentOutOfRangeException(nameof(season))
};
var today = Season.Autumn;
Console.WriteLine(DescribeSeason(today));
棄置模式(_)處理任何未明確列出的值。 由於列舉的底層型別是整數,變數可能包含不對應任何命名成員的值。 例如, (Season)99 在執行時有效。 丟棄模式確保交換運算式能安全地處理這些意外值。
模式匹配 是一種 C# 功能,用來測試一個數值與形狀或條件的關係。 在這個例子中,每個 case 單位檢查枚舉是否與特定成員相符。 switch 表達式是多種模式匹配形式之一。 欲了解更多模式匹配資訊,請參閱 模式匹配。
位元標誌
當枚舉代表多個選擇的組合而非單一選擇時,將每個成員定義為二的冪次方,然後應用 FlagsAttribute:
[Flags]
enum FileAccess
{
None = 0,
Read = 1,
Write = 2,
Execute = 4,
ReadWrite = Read | Write,
All = Read | Write | Execute
}
利用運算子合併數值 | ,並用以下方法 HasFlag測試個別旗標:
var permissions = FileAccess.Read | FileAccess.Write;
Console.WriteLine(permissions); // ReadWrite
Console.WriteLine(permissions.HasFlag(FileAccess.Read)); // True
Console.WriteLine(permissions.HasFlag(FileAccess.Execute)); // False
屬性 [Flags] 也會影響 ToString()。 它以逗號分隔的名稱(例如 Read, Write)顯示合併值,而非原始數字。 如需詳細資訊,請參閱System.FlagsAttribute。
在枚舉與整數之間轉換
明確的型別轉換表達式 用於在列舉與其底層整數型別之間進行轉換。 顯式轉型使用(Type)value語法結構告訴編譯器您打算進行轉換:
var status = HttpStatus.NotFound;
ushort code = (ushort)status;
Console.WriteLine($"Status: {status} ({code})"); // Status: NotFound (404)
var fromCode = (HttpStatus)200;
Console.WriteLine(fromCode); // OK
請注意,將整數強制轉換為列舉類型並無法驗證該值是否符合定義的成員。 當你接受外部數字輸入時,請使用 Enum.IsDefined 檢查其有效性。
解析字串與迭代值
Enum基底類別提供解析字串及遍歷所有定義值的方法:
// Parse a string to an enum value:
var parsed = Enum.Parse<Season>("Winter");
Console.WriteLine(parsed); // Winter
// Try to parse safely. It returns false only when the input can't be parsed. Call Enum.IsDefined to validate named members:
if (Enum.TryParse<Season>("Monsoon", out var unknown))
{
Console.WriteLine(unknown);
}
else
{
Console.WriteLine("'Monsoon' is not a valid Season"); // 'Monsoon' is not a valid Season
}
// Iterate over all values in an enum:
foreach (var season in Enum.GetValues<Season>())
{
Console.WriteLine($"{season} = {(int)season}");
}
// Spring = 0
// Summer = 1
// Autumn = 2
// Winter = 3
當輸入可能無效時,請使用 Enum.TryParse<TEnum>(String, Boolean, TEnum) 代替 Enum.Parse<TEnum>(String) 。 它會回來 false 而不是拋出例外。