c#利用反射实现对类中的常量进行取值和对应常量的注释
因为业务需要,项目中有大量的错误码,还是通过分部类编写,报错之后返回一个错误码,无处可以方便的查询,
后来发现代码中每个错误码都有定义,而且都还有注释,因此考虑通过反射实现读取然后格式化形成错误码文档方便参阅。
读取注释
首先先读取注释,注释只要是标准的///
生成的就能读取,因为每个项目可以生成一个对应的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":"服务器已接受请求,但尚未处理。"}]
参考文档
- Getting a list of constants using Reflection https://weblogs.asp.net/whaggard/2708
- 请问如何通过反射机制获取一个类的常量值 https://social.msdn.microsoft.com/Forums/zh-CN/b39303fa-5f3d-4bef-ac5e-06e5ad095df2/35831383822291420309368903680721453235562642621046337192146219?forum=visualcshartzhchs
- XPath 语法 http://www.w3school.com.cn/xpath/xpath_syntax.asp
- BindingFlags 枚举 https://msdn.microsoft.com/zh-cn/library/cexkb29a

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
C# 编程中的堆栈(Stack)和队列(Queue)
原文: C# 编程中的堆栈(Stack)和队列(Queue) 一、什么是堆?(Heap) 堆是无序的,是一片不连续的内存域,由用户自己来控制和释放,如果用户自己不释放的话,当内存达到一定的特定值时,通过垃圾回收器(GC)来回收。 是程序运行期间动态分配的内存空间,你可以根据程序的运行情况确定要分配的堆内存的大小。 二、什么是栈?(Stack) 栈是有顺序的,是一片连续的内存域,保持着先进后出的原则,由系统自动分配和维护。 是编译期间就分配好的内存空间,因此代码中必须就栈的大小有明确的定义。 表尾允许进行插入删除操作,称为栈顶(Top),另一端是固定的,称为栈底(Bottom)。 PS: 线性表(Linear List)是具有相同特性的数据元素的一个有限序列。 堆栈(Stack)是一种特殊的线性表,是一种操作只允许在尾端进行插入或删除等操作的线性表。 顺序栈(Sequence Stack)是用一片连续的存储空间来存储栈中的数据元素。 链栈(Linked Stack)是用链式存储结构来存储的栈,链栈通常用单链表来表示。 三、什么是堆栈? 由堆和栈...
-
下一篇
Harbor HA部署-使用Ceph RADOS后端
目录1. 前言2. 配置Ceph radosgw用户3. 部署HA的MariaDB集群4. 部署HA的Redis集群5. 部署Harbor集群参考资料 1. 前言 Harbor 1.4.0版本开始提供了HA部署方式,和非HA的主要区别就是把有状态的服务分离出来,使用外部集群,而不是运行在本地的容器上。而无状态的服务则可以部署在多个节点上,通过配置上层Load Balancer构成HA。 这些有状态的服务包括: Harbor database(MariaDB) Clair database(PostgresSQL) Notary database(MariaDB) Redis 我们的Harbor没有使用notary和clair,所以只需要预先准备高可用的MariaDB和Redis集群。多个Harbor节点配置使用相同的MariaDB和Redis地址,就构成了HA集群。 另外多个Registry需要使用共享存储,可选的有Swift、NFS、S3、azure、GCS、Ceph和OSS。我们选择使用Ceph。 docker-registry在2.4.0版本之后移除了rados storage...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS关闭SELinux安全模块
- CentOS8编译安装MySQL8.0.19
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Dcoker安装(在线仓库),最新的服务器搭配容器使用
- SpringBoot2全家桶,快速入门学习开发网站教程
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Docker快速安装Oracle11G,搭建oracle11g学习环境