首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 列舉型別 完整指南:底層型別、Flags 屬性、位元運算、模式比對與最佳實踐

     編輯:關於C語言

列舉基礎語法

// 預設底層型別為 int,值從 0 遞增
enum Color { Red, Green, Blue }

// 指定底層型別 (byte, sbyte, short, ushort, int, uint, long, ulong)
enum ColorByte : byte { Red = 6, Green = 8, Blue = 10 }

// 明確指定數值 (可重複、可不連續)
enum Status { Unknown = -1, Failed = 0, Success = 1, Pending = 100 }

Flags 屬性:位元旗標列舉

[Flags]
enum FileAccess
{
    None = 0,
    Read = 1,      // 2^0
    Write = 2,     // 2^1
    Execute = 4,   // 2^2
    ReadWrite = Read | Write, // 3
    All = Read | Write | Execute // 7
}

// 使用
FileAccess access = FileAccess.Read | FileAccess.Write; // 3
bool canRead = (access & FileAccess.Read) != 0; // true
bool canExec = access.HasFlag(FileAccess.Execute); // false (C# 4+)

// 列舉所有旗標
foreach (FileAccess flag in Enum.GetValues(typeof(FileAccess)))
{
    if (access.HasFlag(flag) && flag != FileAccess.None)
        Console.WriteLine(flag); // Read, Write
}

核心靜態方法 (System.Enum)

方法說明範例
GetValues取得所有值陣列Enum.GetValues(typeof(Color))
GetNames取得所有名稱字串陣列Enum.GetNames(typeof(Color))
Parse字串轉列舉 (區分大小寫)Enum.Parse("Red")
TryParse安全轉換,回傳 boolEnum.TryParse("Red", out Color c)
IsDefined檢查值是否定義於列舉Enum.IsDefined(typeof(Color), 99)
GetName值轉名稱Enum.GetName(typeof(Color), 0)
HasFlagFlags 列舉檢查旗標access.HasFlag(FileAccess.Read)

型別轉換與底層值存取

Color c = Color.Red;
int underlying = (int)c; // 0
byte b = (byte)ColorByte.Red; // 6

// 取得底層型別
Type underlyingType = Enum.GetUnderlyingType(typeof(ColorByte)); // System.Byte

進階:模式比對 (C# 7+) 與 Switch Expression (C# 8+)

public string Describe(Color color) => color switch
{
    Color.Red => "紅色:熱情",
    Color.Green => "綠色:自然",
    Color.Blue => "藍色:冷靜",
    _ => "未知顏色"
};

// 結合屬性模式
public string DescribeStatus(Status s) => s switch
{
    Status.Success => "成功",
    Status.Failed => "失敗",
    Status.Pending => "待處理",
    _ when s < 0 => "錯誤狀態",
    _ => $"未定義代碼:{(int)s}"
};

效能考量:避免 Boxing

// 不好:每次 ToString() 都會 Boxing
string s1 = color.ToString(); 

// 較好:使用 nameof 或預先快取
string s2 = nameof(Color.Red); // 編譯期常數 "Red"

// Flags 列舉格式化
[Flags] enum Perm { None=0, R=1, W=2, X=4 }
Perm p = Perm.R | Perm.W;
Console.WriteLine(p); // 輸出 "R, W" (自動解析 Flags)
Console.WriteLine(p.ToString("F")); // "R, W" 完整旗標名
Console.WriteLine(p.ToString("D")); // "3" 數值
Console.WriteLine(p.ToString("X")); // "00000003" 十六進位

最佳實踐清單

  1. 單一值列舉:預設 int 即可,值從 0 開始
  2. Flags 列舉:必須加 [Flags]、值用 2 的冪次、提供 None = 0
  3. 底層型別:預設 int;記憶體敏感或互通需求才用 byte/short
  4. 命名慣例:列舉型別單數 PascalCase (Color);成員 PascalCase (Red);Flags 列舉型別複數 (FileAccess)
  5. 避免公開列舉變更:公開 API 的列舉一旦發布,增減成員會破壞二進位相容性
  6. 使用 Enum.IsDefined 驗證外部輸入,防止非法值

實用擴充方法

public static class EnumExtensions
{
    public static IEnumerable GetFlags(this T value) where T : Enum
    {
        foreach (T flag in Enum.GetValues(value.GetType()))
            if (value.HasFlag(flag) && !flag.Equals(default(T)))
                yield return flag;
    }
    
    public static string ToDescription(this T value) where T : Enum
    {
        var field = value.GetType().GetField(value.ToString());
        var attr = field?.GetCustomAttribute();
        return attr?.Description ?? value.ToString();
    }
}

// 使用
[Flags] enum Perm { None=0, R=1, W=2 }
Perm p = Perm.R | Perm.W;
foreach (var f in p.GetFlags()) Console.WriteLine(f); // R, W
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved