FlagsAttribute 與 Enum 設計準則
核心規則
- **僅在需位運算 (AND/OR/XOR) 時** 使用
[Flags]
- 枚舉值用 **2 的冪次** (1, 2, 4, 8...) 確保位不重疊
- 考慮提供**常用組合常量**:
ReadWrite = Read | Write
- **謹慎使用負數** 作為旗標值(易混淆、易出錯)
- 測試旗標是否設置:
(value & flag) == flag
- 零值命名為
None;邏輯比較用 (value & None) != 0 檢測是否有旗標
- 非旗標枚舉也建議定義
None = 0(CLR 預設初始化為 0)
- 零值可表示「預設情況」或「無對應狀態」
- **不要**定義僅反映枚舉自身狀態的值(如標記末尾)
- **不要**保留未來用的枚舉值
- 方法/屬性接受枚舉時,**驗證有效性**(可強制轉型繞過定義)
實戰範例:權限系統
[Flags]
public enum Permission
{
None = 0,
Select = 1, // 0001
Edit = 2, // 0010
Delete = 4, // 0100
View = 8, // 1000
ReadWrite = Select | Edit, // 0011 = 3
FullControl = Select | Edit | Delete | View // 1111 = 15
}
技巧 1:移除特定旗標
public static Permission ClearFlag(Permission value, Permission flag)
{
// value & (All ^ flag) 等價於 value & ~flag
return value & (Permission.FullControl ^ flag);
}
// 使用範例
Permission p = Permission.FullControl; // 15
p = ClearFlag(p, Permission.Delete); // 移除 Delete (4) → 11 (Select|Edit|View)
技巧 2:檢測旗標
// 位運算檢測(推薦)
bool hasEdit = (p & Permission.Edit) == Permission.Edit;
// 邏輯檢測零值
bool hasAny = p != Permission.None;
技巧 3:遍歷所有旗標
foreach (Permission flag in Enum.GetValues(typeof(Permission)))
{
if (flag != Permission.None && (p & flag) == flag)
Console.WriteLine($"Has: {flag}");
}
常見錯誤避坑
| 錯誤 | 正確 |
| 枚舉值用 1,2,3,4 | 用 1,2,4,8 (2的冪次) |
| 用 (value & flag) != 0 檢測 | 用 (value & flag) == flag |
| [Flags] 用於非位運算枚舉 | 僅位運算需求加 [Flags] |
| 負數作旗標 | 避免負數,改用高位正數 |