枚舉不僅是常量集合,更是領域建模的利器。本文總結實戰中三大進階用法:Flags 位運算組合、泛型本地化擴展、ORM 無縫映射,讓枚舉從「代碼裡的數字」變為「業務語言的直觀表達」。
為枚舉標記 [Flags],賦予 2 的冪次值,即可進行集合式運算:
[Flags]
public enum MicrosoftTech {
CSharp = 1, // 0001
AspNetMvc = 2, // 0010
SqlServer = 4, // 0100
Wcf = 8, // 1000
Silverlight = 16 // 10000
}
// 組合技能
var skills = MicrosoftTech.CSharp | MicrosoftTech.AspNetMvc; // 0011 = 3
// 檢測是否擁有某技能
bool hasCSharp = (skills & MicrosoftTech.CSharp) != 0; // true
// 移除技能
skills &= ~MicrosoftTech.AspNetMvc; // 0011 & 1101 = 0001
// 切換技能
skills ^= MicrosoftTech.SqlServer; // 翻轉第 3 位
// 遍歷所有包含的標誌
foreach (MicrosoftTech tech in Enum.GetValues(typeof(MicrosoftTech))) {
if ((skills & tech) != 0) Console.WriteLine(tech);
}
優勢:編譯器保證類型安全,IDE 智能提示,避免魔術數字,ToString() 自動輸出 "CSharp, AspNetMvc"。
利用 ResourceManager + 泛型,一行代碼獲取本地化顯示名:
public static class EnumExtensions {
private static readonly ResourceManager _res =
new ResourceManager("Resources.Enums", Assembly.GetExecutingAssembly());
public static string GetDisplayName(this T value) where T : Enum {
string key = $"{typeof(T).Name}.{value}";
return _res.GetString(key) ?? value.ToString();
}
public static List> GetLocalizedList() where T : Enum {
return Enum.GetValues(typeof(T))
.Cast()
.Select(v => new KeyValuePair(
Convert.ToInt32(v), v.GetDisplayName()))
.ToList();
}
}
資源文件 (Resources.Enums.resx):
| Name | Value (zh-CN) | Value (en-US) |
|---|---|---|
| MicrosoftTech.CSharp | C# | C# |
| MicrosoftTech.AspNetMvc | ASP.NET MVC | ASP.NET MVC |
| MicrosoftTech.SqlServer | SQL Server | SQL Server |
用法:
var tech = MicrosoftTech.CSharp;
Console.WriteLine(tech.GetDisplayName()); // "C#"
var list = EnumExtensions.GetLocalizedList();
// 綁定到下拉框:Value=數值, Text=本地化名稱
以 LINQ to SQL / Entity Framework 為例:
public enum CustomerType {
Trader = 0,
Supplier = 1,
Logistics = 2
}
[Table("Customers")]
public class Customer {
[Column] public int Id { get; set; }
[Column] public string Name { get; set; }
// 數據庫存 int,實體屬性為強類型枚舉
[Column(Name = "CustomerType")]
public CustomerType Type { get; set; }
}
// 查詢
var traders = db.Customers.Where(c => c.Type == CustomerType.Trader).ToList();
// 生成 SQL: SELECT ... WHERE CustomerType = 0
// 無需硬編碼 0/1/2,重構安全,業務語義清晰
進階:值轉換器 (EF Core 2.1+)
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity()
.Property(e => e.Type)
.HasConversion(); // 顯式指定數值轉換
}
None = 0,便於判斷是否賦值StringEnumConverter 輸出字符串| 場景 | 推薦 | 備選 |
|---|---|---|
| 固定業務狀態集 (訂單狀態、用戶角色) | Enum | 查表 + 外鍵 |
| 需組合的標誌集 (權限、特性、配置開關) | [Flags] Enum | 位掩碼 int |
| 需本地化顯示、描述、圖標等豐富元數據 | Enum + Resource/Attribute | 類 + 靜態實例 |
| 頻繁新增、運行時動態擴展 | 數據庫表 + 緩存 | - |
| 需行為、邏輯、驗證 | 類 (Smart Enum 模式) | - |
枚舉是 C# 最被低估的領域建模工具。Flags 賦予集合代數能力,泛型擴展實現國際化解耦,ORM 映射消除魔術數字——三招合一,讓枚舉成為業務語言在代碼中的精確投影。下次定義 enum Status { A, B, C } 時,請問自己:它需要組合嗎?需要多語言嗎?需要進數據庫嗎?答案在其中。