反射前传-遍历枚举类型
本文不会深入讲解反射,只是完成一个小功能:遍历枚举类型。在后续的文章里会具体讲解反射技术。
在.NET中,提供了System.Type类和System.Reflection命名空间来帮助我们实现这个功能。
Type抽象类提供了访问类型元数据的能力,当实例化了一个Type对象后,可以通过它的属性和方法,获取类型的元数据信息,或者进一步获得该类型的成员的元数据信息。
注意到这里,因为Type对象总是基于某一具体类型的,并且它是一个抽象类,所以在创建Type对象时,需要提供具体类型的名称或者具体类型的实例。
首先创建一个枚举类型WeekDay:
public enum WeekDay
{
[Description("This is 1st of week.")]
Monday = 1,
[Description("This is 2st of week.")]
Tuesday,
[Description("This is 3st of week.")]
Wednesday,
[Description("This is 4st of week.")]
Thursday,
[Description("This is 5st of week.")]
Friday,
[Description("This is 6st of week.")]
Saturday,
[Description("This is 7st of week.")]
Sunday
}
里面有枚举字段的值,字段名称,和描述信息。
通过下面的方法可以获取枚举中的所有值:
//获取枚举类型的枚举值
public static List<EnumItem> GetEnumItems()
{
List<EnumItem> items = new List<EnumItem>();
//typeof运算符得到具体类型的Type对象
Type type = typeof(WeekDay);
//调用Type对象的GetFields()方法,返回Type对象所表示的具体类型中定义的所有字段
var fields = type.GetFields();
foreach (var field in fields)
{
//过滤掉具体类型中系统自带的一些特殊字段
if (!field.IsSpecialName)
{
EnumItem item = new EnumItem();
//获取具体类型中定义的字段的静态值,即枚举的值
item.Value = (int)field.GetRawConstantValue();
//获取具体类型中定义的字段的名称
item.Name = field.Name;
//获取具体类型中定义的字段的Description特性值
item.Description = string.Empty;
var descrAttr = field.GetCustomAttribute<DescriptionAttribute>();
if (descrAttr != null)
{
item.Description = descrAttr.Description;
}
items.Add(item);
}
}
return items;
}
代码中,使用了Type对象,FieldInfo对象,DescriptionAttribute对象,通过它们得到了枚举类型中的所有值。
我们再定义一个枚举类型Months:
public enum Months
{
January = 1,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December
}
我们想遍历Months类型的枚举值,和上面的WeekDay类型的代码一模一样,除了这一行:
//typeof运算符得到具体类型的Type对象
Type type1 = typeof(WeekDay);
Type type2 = typeof(Months);
定义泛型类重用GetEnumItems()代码:
//使用泛型类达到代码重用
public class EnumManager<TEnum>
{
//使用静态构造器,约束泛型只能是枚举类型
//使用非枚举类型,编译可以通过,但是运行时会拋异常
static EnumManager()
{
if (!typeof(TEnum).IsEnum)
{
throw new ArgumentException("TEnum must be an enumerated typeof.");
}
}
//获取枚举类型的枚举值
public static List<EnumItem> GetEnumItems()
{
List<EnumItem> items = new List<EnumItem>();
//typeof运算符得到具体类型的Type对象
Type type = typeof(TEnum);
//调用Type对象的GetFields()方法,返回Type对象所表示的具体类型中定义的所有字段
var fields = type.GetFields();
foreach (var field in fields)
{
//过滤掉具体类型中系统自带的一些特殊字段
if (!field.IsSpecialName)
{
EnumItem item = new EnumItem();
//获取具体类型中定义的字段的静态值,即枚举的值
item.Value = (int)field.GetRawConstantValue();
//获取具体类型中定义的字段的名称
item.Name = field.Name;
//获取具体类型中定义的字段的Description特性值
item.Description = string.Empty;
var descrAttr = field.GetCustomAttribute<DescriptionAttribute>();
if (descrAttr != null)
{
item.Description = descrAttr.Description;
}
items.Add(item);
}
}
return items;
}
}
上面的代码GetEnumItems()方法就可以给所有的枚举类型使用了,达到了代码复用的目的,再说明一点,我们使用了静态构造器对泛型类型参数进行了约束,使类型参数只能是枚举类型才能正常工作。
本文回顾:
遍历枚举类型
泛型类达到代码重用
约束泛型类型只能是枚举类型