對於一個易讀易修改的 code,善用 Enum 來取代單純數值的使用是一種較佳的做法!
然而 Enum 只能對應到數值的應用,若希望有更多的應用 e.g. string、struct、class,etc. 則必須透過為 Enum 附加屬性 (Attribute) 並使用反射 (Reflection) 來取得資訊的方式豐富以 Enum 為出發的系統!
一般的 Enum 通常會是類似這樣的形式:
1 2 3 4 5 6 7
|
public enum SampleEnum { None = 0, MyEnum01, MyEnum02, MyEnum03, };
|
然而這樣的 code 只能達到令 None = 0;MyEnum01 = 1;MyEnum02 = 2;MyEnum03 = 3,這樣的狀態而已,如果我希望 None;MyEnum01 … 可以代表一個對應的字串狀態,那就可以透過為 Enum 加上 Attribute 來表示:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
public enum SampleEnum { [System.ComponentModel.DescriptionAttribute("空的")] None,
[System.ComponentModel.DescriptionAttribute("第一個")] MyEnum01,
[System.ComponentModel.DescriptionAttribute("第二個")] MyEnum02,
MyEnum03, };
|
要為 Enum 加上 Attribute,只需要在要附加屬性的 Enum 上方用中括號來表示要為某個 Enum 添加一個屬性,並且在中括號內輸入一個 Attribute 的 class,如上述的 code 就是用了一個 system 的 description attribute。因此現在 None、MyEnum01、MyEnum02 都被附加上屬性了,而 MyEnum03 則是沒有被附加上屬性。
當然,若 system 的 description attribute 無法滿足你的需求時,也可以繼承 Attribute Abstract Class 來創造自己的 Attribute:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public class SampleEnumAttribute : Attribute { private string _text = string.Empty;
public SampleEnumAttribute(string text) { _text = text; }
public string Text => _text; }
/* 就可以將上面的 "System.ComponentModel.DescriptionAttribute" 取代成 "SampleEnumAttribute" */ public enum SampleEnum { [SampleEnumAttribute("空的")] None,
[SampleEnumAttribute("第一個")] MyEnum01,
[SampleEnumAttribute("第二個")] MyEnum02,
MyEnum03, };
|
接著就可以透過 Reflection 來獲得 Attribute 中的資訊:
※ 以下為自定義擴充方法的寫法,若尚不清楚此種用法可以參考:[C#] 如何添加自己的擴充功能讓功能更完善
1 2 3 4 5 6 7 8 9 10 11 12 13
|
public static class SampleEnumExtension { public static string GetSampleEnumText(this SampleEnum sample) { System.Reflection.FieldInfo fi = sample.GetType().GetField(sample.ToString()); if (fi.GetCustomAttribute(typeof(SampleEnumAttribute), false) is SampleEnumAttribute attribute) { return attribute.Text; } else return null; } }
|
將上述提到的附加屬性 (Attribute) 的方法搭配反射 (Reflection) 結合起來使用,就可以得到如下的結果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
private static void Main(string[] args) { var text = string.Empty; Console.WriteLine("/// ); text = SampleEnum.None.GetSampleEnumText(); Console.WriteLine($"/// {nameof(SampleEnum.None)} 的 Attribute 訊息: {text}, {nameof(string.IsNullOrEmpty)}: {string.IsNullOrEmpty(text)}"); text = SampleEnum.MyEnum01.GetSampleEnumText(); Console.WriteLine($"/// {nameof(SampleEnum.MyEnum01)} 的 Attribute 訊息: {text}, {nameof(string.IsNullOrEmpty)}: {string.IsNullOrEmpty(text)}"); text = SampleEnum.MyEnum02.GetSampleEnumText(); Console.WriteLine($"/// {nameof(SampleEnum.MyEnum02)} 的 Attribute 訊息: {text}, {nameof(string.IsNullOrEmpty)}: {string.IsNullOrEmpty(text)}"); text = SampleEnum.MyEnum03.GetSampleEnumText(); Console.WriteLine($"/// {nameof(SampleEnum.MyEnum03)} 的 Attribute 訊息: {text}, {nameof(string.IsNullOrEmpty)}: {string.IsNullOrEmpty(text)}"); Console.WriteLine("/// "); Console.ReadLine(); }
/// /// None 的 Attribute 訊息: 空的, IsNullOrEmpty: False /// MyEnum01 的 Attribute 訊息: 第一個, IsNullOrEmpty: False /// MyEnum02 的 Attribute 訊息: 第二個, IsNullOrEmpty: False /// MyEnum03 的 Attribute 訊息: , IsNullOrEmpty: True ///
|
可以得到 None、MyEnum01、MyEnum02 的字串訊息、並且 MyEnum03 因為沒有附加 Attribute 所以返回的 string 為 null。
完整的 sample code 我放在 github 上了,歡迎下載玩玩看!
github sample code:https://github.com/leoli-git/MySampleCode/tree/main/MyEnum