首先需要從內部瞭解一下枚舉(Enumeration),相信許多人已經知道了,當我們聲明一個這樣的枚舉類型:
enum MyEnum
{
AAA, BBB, CCC
}
背後的IL是這樣的:
.class private auto ansi sealed MyEnum
extends [mscorlib]System.Enum
{
.field public static literal valuetype Mgen.MyEnum AAA = int32(0)
.field public static literal valuetype Mgen.MyEnum BBB = int32(1)
.field public static literal valuetype Mgen.MyEnum CCC = int32(2)
.field public specialname rtspecialname int32 value__
}
那沒,其實枚舉中的常量都是靜態欄位。而枚舉對象的值會儲存在非靜態特殊欄位value__中。
因此,用反射來擷取名稱其實就是擷取類型的所有靜態欄位就可以了,如下代碼:
var fields = typeof(MyEnum).GetFields(BindingFlags.Static | BindingFlags.Public);
foreach (var fi in fields)
Console.WriteLine(fi.Name);
輸出:
AAA
BBB
CCC
對於值得擷取也很簡單,通過反射得到的代表靜態欄位的FieldInfo來擷取值就可以,並且擷取的值仍屬於枚舉類型的。如果想擷取枚舉背後的類型,仍需要Enum.GetUnderlyingType方法,如下代碼:
var fields = typeof(MyEnum).GetFields(BindingFlags.Static | BindingFlags.Public);
foreach (var fi in fields)
{
var value = fi.GetValue(null);
Console.WriteLine("值:{0} 類型:{1} 枚舉背後類型:{2}",
value, value.GetType(), Enum.GetUnderlyingType(value.GetType()));
}
輸出:
值:AAA 類型:Mgen.MyEnum 枚舉背後類型:System.Int32
值:BBB 類型:Mgen.MyEnum 枚舉背後類型:System.Int32
值:CCC 類型:Mgen.MyEnum 枚舉背後類型:System.Int32
最後擷取特性,通過MemberInfo類型的GetCustomAttributes方法或者Attribute類型的靜態方法都可以,比如在枚舉值上加一個特性:
enum MyEnum
{
AAA, BBB,
[Obsolete]
CCC
}
代碼:
var fields = typeof(MyEnum).GetFields(BindingFlags.Static | BindingFlags.Public);
foreach (var fi in fields)
Console.WriteLine(Attribute.GetCustomAttribute(fi, typeof(ObsoleteAttribute), false) != null);
輸出:
False
False
True