浅谈.Net反射 1

反射前传-遍历枚举类型

本文不会深入讲解反射,只是完成一个小功能:遍历枚举类型。在后续的文章里会具体讲解反射技术。

在.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()方法就可以给所有的枚举类型使用了,达到了代码复用的目的,再说明一点,我们使用了静态构造器对泛型类型参数进行了约束,使类型参数只能是枚举类型才能正常工作。

本文回顾:

遍历枚举类型

泛型类达到代码重用

约束泛型类型只能是枚举类型

本文分享自微信公众号 - 明丰随笔(liumingfengwx2)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券