首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> C# 入門

C# 列舉完整指南:定義、Flags 屬性、模式比對與最佳實踐

     編輯:C# 入門

C# 列舉完整指南:定義、Flags 屬性、模式比對與最佳實踐

列舉 是一組具名整數常數的實值型別,讓程式碼用有意義的名稱取代魔術數字,提升可讀性與型別安全。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

模式比對與 Switch 運算式

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 { ... }

最佳實踐

  • 命名慣例:型別名稱單數 PascalCase(DayOfWeek),成員 PascalCase;Flags 列舉型別名稱用複數(FileAccess)。
  • 預設值為 0:第一個成員設為 None = 0,對應預設值語意。
  • 避免保留字:成員名稱勿使用 C# 關鍵字,否則需用 @ 前綴。
  • Flags 列舉數值設計:嚴格使用 2 的冪次,提供常用組合常數(如 ReadWrite)。
  • 不要頻繁變更數值:已序列化/持久化的列舉數值變更會破壞相容性。
  • 優先用列舉而非常數類別:列舉提供型別安全、IDE 自動完成、編譯期檢查。

常見問題 FAQ

Q: 列舉可以繼承嗎?

A: 不能。列舉隱含繼承 System.Enum,不可再繼承其他型別,也不可被繼承。

Q: 可以為列舉加上方法嗎?

A: 不能直接在列舉定義方法,但可撰寫擴充方法達成同樣效果。

Q: 如何安全地將整數轉為列舉?

public static T SafeParse(int value) where T : Enum {
    return Enum.IsDefined(typeof(T), value) ? (T)(object)value : default;
}

Q: 列舉底層型別用什麼?

A: 絕大多數用預設 int。需節省記憶體(大量陣列)或互通原生程式碼時,考慮 byte/short。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved