列舉 是一組具名整數常數的實值型別,讓程式碼用有意義的名稱取代魔術數字,提升可讀性與型別安全。C# 列舉底層為整數型別(預設 int),支援 byte、sbyte、short、ushort、int、uint、long、ulong。
// 預設 int,從 0 開始遞增
public enum DayOfWeek {
Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
}
// 指定底層型別與自訂數值
public enum HttpStatusCode : ushort {
OK = 200,
Created = 201,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
InternalServerError = 500
}
// 手動指定部分數值,其餘自動遞增
public enum Priority {
Low = 1,
Medium = 5,
High = 10, // 10
Critical // 11 (自動 +1)
}
var day = DayOfWeek.Monday;
int value = (int)day; // 1
string name = day.ToString(); // "Monday"
DayOfWeek parsed = Enum.Parse("Tuesday"); // 忽略大小寫
bool isValid = Enum.IsDefined(typeof(DayOfWeek), 7); // false (範圍 0-6)
// 取得所有名稱/值
string[] names = Enum.GetNames();
Array values = Enum.GetValues();
使用 [Flags] 屬性表示可組合的位元選項,數值必須為 2 的冪次:
[Flags]
public enum FileAccess {
None = 0,
Read = 1, // 0001
Write = 2, // 0010
Execute = 4, // 0100
Delete = 8, // 1000
ReadWrite = Read | Write, // 3 (0011)
All = Read | Write | Execute | Delete // 15 (1111)
}
// 使用位元運算
var access = FileAccess.Read | FileAccess.Write; // ReadWrite
bool canRead = access.HasFlag(FileAccess.Read); // true (C# 4.0+)
bool canDelete = access.HasFlag(FileAccess.Delete); // false
// 移除旗標
access &= ~FileAccess.Write; // 僅剩 Read
注意:HasFlag 處理 None=0 有特殊行為,建議自行用位元運算檢查:(access & FileAccess.Read) != 0。
為列舉加上擴充方法,豐富行為:
public static class HttpStatusCodeExtensions {
public static bool IsSuccess(this HttpStatusCode code) =>
(int)code >= 200 && (int)code < 300;
public static bool IsClientError(this HttpStatusCode code) =>
(int)code >= 400 && (int)code < 500;
public static string GetDescription(this HttpStatusCode code) => code switch {
HttpStatusCode.OK => "請求成功",
HttpStatusCode.NotFound => "找不到資源",
_ => code.ToString()
};
}
// 使用
var status = HttpStatusCode.NotFound;
Console.WriteLine(status.GetDescription()); // "找不到資源"
Console.WriteLine(status.IsClientError()); // True
C# 7.0+ 讓列舉處理更優雅:
public static string HandleStatus(HttpStatusCode status) => status switch {
HttpStatusCode.OK => "繼續處理",
HttpStatusCode.Created => "資源已建立",
HttpStatusCode.NoContent => "無內容回傳",
>= HttpStatusCode.BadRequest and < HttpStatusCode.InternalServerError => "用戶端錯誤",
>= HttpStatusCode.InternalServerError => "伺服器錯誤",
_ => "未知狀態"
};
JSON 序列化預設輸出數值,可自訂為字串:
// System.Text.Json
var options = new JsonSerializerOptions {
Converters { new JsonStringEnumConverter() }
};
// Newtonsoft.Json
[JsonConverter(typeof(StringEnumConverter))]
public enum MyEnum { ... }
DayOfWeek),成員 PascalCase;Flags 列舉型別名稱用複數(FileAccess)。None = 0,對應預設值語意。@ 前綴。ReadWrite)。A: 不能。列舉隱含繼承 System.Enum,不可再繼承其他型別,也不可被繼承。
A: 不能直接在列舉定義方法,但可撰寫擴充方法達成同樣效果。
public static T SafeParse(int value) where T : Enum {
return Enum.IsDefined(typeof(T), value) ? (T)(object)value : default;
}
A: 絕大多數用預設 int。需節省記憶體(大量陣列)或互通原生程式碼時,考慮 byte/short。