• c#利用反射实现对类中的常量进行取值和对应常量的注释


    C#利用反射实现对类中的常量进行取值和对应常量的注释

    项目示例:https://gitee.com/dhclly/IceDog.GenerateErrorCode

    因为业务需要,项目中有大量的错误码,还是通过分部类编写,报错之后返回一个错误码,无处可以方便的查询,
    后来发现代码中每个错误码都有定义,而且都还有注释,因此考虑通过反射实现读取然后格式化形成错误码文档方便参阅。

    读取注释

    首先先读取注释,注释只要是标准的///生成的就能读取,因为每个项目可以生成一个对应的xml注释文档,这个功能默认
    未开启,需要在要读取的类所在项目的名称上右键然后选择属性-生成-xml文档文件勾选上了并引入此项目,重新生成当前项目。
    这样在输出目录中就存在了xml文档了。

    实现代码

    首先代码不多,其次,代码中有详细注释,就不多说了,代码如下

    这是需要解析的类示例:

    /// <summary>
    /// 状态码类,存储状态码常量,这里的常量是http的状态码,用于反射解析
    /// </summary>
    public class StatusCode
    {
        /// <summary>
        /// 客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。
        /// </summary>
        public const int Continue = 100;
        /// <summary>
        /// 代表处理将被继续执行。
        /// </summary>
        public const int Processing = 102;
        /// <summary>
        /// 请求已成功,请求所希望的响应头或数据体将随此响应返回。
        /// </summary>
        public const int Ok = 200;
        /// <summary>
        /// 请求已经被实现,而且有一个新的资源已经依据请求的需要而创建,且其URI已经随Location头信息返回。
        /// </summary>
        public const int Created = 201;
        /// <summary>
        /// 服务器已接受请求,但尚未处理。
        /// </summary>
        public const int Accepted = 202;
    }
    
    

    这是存储用的模型

    /// 用于存储解析好的属性
    /// </summary>
    public class StatusCodeModel
    {
        /// <summary>
        /// 状态码的全名
        /// </summary>
        public string FullName { get; set; }
        /// <summary>
        /// 状态码的名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 状态码的值
        /// </summary>
        public int Value { get; set; }
        /// <summary>
        /// 状态码的注释
        /// </summary>
        public string Note { get; set; }
    }
    

    核心实现:

    public void Test()
    {
        //读取注释
    
        //是从xx.xml文件里面读取,所以要确保要读取的类所在项目的属性-生成-xml文档文件勾选上了并引入此项目,重新生成当前项目
        string filePath = Environment.CurrentDirectory + @"IceDog.DNL.CSharp.Grammar.xml";
        XmlDocument xml = new XmlDocument();
        //加载xml文件
        xml.Load(filePath);
        //用于存储解析出来的xml注释
        var dictNote = new Dictionary<string, string>();
        //可以查看xml文档格式然后可以通过如下XPath表达式获取相关节点内容
        var memebers = xml.SelectNodes("/doc/members/member");
        foreach (object m in memebers)
        {
            //判断是否转换类型成功
            if (m is XmlNode node)
            {
                //获取member节点的属性-名称
                XmlAttribute propName = node.Attributes["name"];
                string propNameValue = propName.Value;
                //里面还有一层summary节点,因为我们解析的是常量节点,
                //不会包含其他节点,所以不用进一步读取子节点
                var value = node.InnerText.Trim();
                //用于匹配的key
                var matchKey = "F:IceDog.DNL.CSharp.Grammar.Reflection.Constant.StatusCode.";
                //通过name值进行解析,目前发现的前缀有 F:field,M:method,T;type,P:property
                if (propNameValue.IndexOf(matchKey, StringComparison.Ordinal) > -1)
                {
                    //去掉前缀和冒号,然后赋值
                    dictNote[propNameValue.Substring(2)] =value;
                }
            }
        }
        //解析常量对象
    
        //存储解析的内容
        var codeList = new List<StatusCodeModel>();
        var constants = new ArrayList();
        Type type = typeof(StatusCode);
        //从规定的约束内搜索字段
        //约束有是静态成员,是公共成员,和返回父级的公共静态成员,
        FieldInfo[] infoList = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);
    
        foreach (FieldInfo info in infoList)
        {
            //按照要解析的字段的特性来判断,
            //常量是字面量,不可以在构造函数中初始化
            if (info.IsLiteral && !info.IsInitOnly)
            {
                constants.Add(info);
            }
        }
        //常量信息列表
        var constantInfoList = (FieldInfo[])constants.ToArray(typeof(FieldInfo));
        foreach (FieldInfo info in constantInfoList)
        {
            var scm = new StatusCodeModel
            {
                Value = (int)info.GetRawConstantValue(),
                Name = info.Name,
                FullName = info.DeclaringType.FullName + "." + info.Name
            };
            scm.Note = dictNote[scm.FullName];
            codeList.Add(scm);
        }
        //通过值进行升序排序
        codeList.Sort((m1, m2) => m1.Value - m2.Value);
    
        //接下来就可以进行自己需要的操作了,
        //这里是json序列化
        var str = JsonConvert.SerializeObject(codeList);
        Console.WriteLine(str);
    }
    

    输出结果如下

    [{"FullName":"IceDog.DNL.CSharp.Grammar.Reflection.Constant.StatusCode.Continue","Name":"Continue","Value":100,"Note":"客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。"},{"FullName":"IceDog.DNL.CSharp.Grammar.Reflection.Constant.StatusCode.Processing","Name":"Processing","Value":102,"Note":"代表处理将被继续执行。"},{"FullName":"IceDog.DNL.CSharp.Grammar.Reflection.Constant.StatusCode.Ok","Name":"Ok","Value":200,"Note":"请求已成功,请求所希望的响应头或数据体将随此响应返回。"},{"FullName":"IceDog.DNL.CSharp.Grammar.Reflection.Constant.StatusCode.Created","Name":"Created","Value":201,"Note":"请求已经被实现,而且有一个新的资源已经依据请求的需要而创建,且其URI已经随Location头信息返回。"},{"FullName":"IceDog.DNL.CSharp.Grammar.Reflection.Constant.StatusCode.Accepted","Name":"Accepted","Value":202,"Note":"服务器已接受请求,但尚未处理。"}]
    

    参考文档

  • 相关阅读:
    WPF/MVVM 快速开始指南(译)
    Rose2003的安装和破解
    自定义vs代码段
    silverlight中Grid.ColumnDefinitions属性设置错误
    vs绑定和取消绑定项目和解决方案
    firefox浏览器中silverlight无法输入问题
    silverlight中当前上下文中不存在名称“InitializeComponent“错误
    inotify使用代码
    build android toochain on mac (gcc 4.4.3 compile)
    istat 一个不错的widget
  • 原文地址:https://www.cnblogs.com/DHclly/p/9223326.html
Copyright © 2020-2023  润新知