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":"服务器已接受请求,但尚未处理。"}]
参考文档
- 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
c#利用反射实现对类中的常量进行取值和对应常量的注释的更多相关文章
- Springboot在包含有参构造方法的类中使用@Value注解取值
我们在Springboot中经常使用@Value注解来获取配置文件中的值,像下面这样 @Component class A { @Value("${user.value}") pr ...
- Java通过反射机制修改类中的私有属性的值
首先创建一个类包含一个私有属性: class PrivateField{ private String username = "Jason"; } 通过反射机制修改username ...
- C# 中利用反射机制拷贝类的字段和属性(拷贝一个类对象的所有东西付给另一个类对象,而不是付给引用地址)
from:https://blog.csdn.net/poxiaohai2011/article/details/27555951 //C# 中利用反射机制拷贝类的字段和属性(拷贝一个类对象的所有东西 ...
- 利用反射创建User类的对象
package com.bjpowernode; public class User { private int age; public String name; public void m1() { ...
- Android反射出一个类中的其他类对象并调用其对应方法
MainActivity如下: package cn.testreflect; import java.lang.reflect.Field; import java.lang.reflect.Met ...
- hibernate的dao中参数的传递取值
hibernate的dao中参数的传递取值 private Query setParameter(Query query, Map<String, Object> map) { if (m ...
- 关于JAVA中Byte类型的取值范围的推论(*零为正数,-128在计算机中的表示方法...)
先看一段推理<*一切都是在8个比特位的前提下,讨论二进制的符号位,溢出等等,才有意义*> +124:0111 1100 -124:1000 0100 +125:0111 1101 -125 ...
- ZT: C#不建类直接Json解析与取值
C#不建类直接Json解析与取值 2017年10月19日 15:58:22 圆圆娃哈哈 阅读数:701 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn. ...
- android 利用反射机制获取drawable中所有的图片资源
public List<Map<String,Object>> getGridData() { list=new ArrayList<Map<String,Obje ...
随机推荐
- JAVA基础之Map接口
个人理解: 个人感觉Map接口以后会经常用到,可以很清晰地查找某个对象,要熟悉其四种遍历方法.特别注意其键值对的键不能是重复的,有想定义有序存取的话,可以使用LinkedHashMap集合.不过定义自 ...
- File类。
File类: java.io.File 类.是文件和文件夹目录名的抽象表示形式. 可以用File对文件和文件夹进行 创建,删除,获取等操作. File类的一些静态成员变量: static String ...
- FastDFS整合Nginx
浏览器访问FastDFS存储的图片需要通过Nginx访问 需要安装fastdfs-nginx-module.Nginx 安装fastdfs-nginx-module模块 (1)将fastdfs-ngi ...
- vue2.0:(七)、vue-resource
本篇文章开始前,先介绍下什么是vue-resource,并且现在还有一个axios. Vue.js是数据驱动的,这使得我们并不需要直接操作DOM,如果我们不需要使用jQuery的DOM选择器,就没有必 ...
- Android里的网格空隙
在很多移动端或者web端开发中我们会遇到很多网格布局,如果我们使用线性布局来实现一些简单的网格布局就需要使用padding/margin等属性来使其对齐,代码如下: <LinearLayout ...
- Oracle关于TX锁的一个有趣的问题
前阵子有一个网友在群里问了一个关于Oracle数据库的TX锁问题,问题原文如下: 请教一个问题: 两个会话执行不同的delete语句,结果都是删除同一个行.先执行的会话里where条件不加索引走全表扫 ...
- 小目标 | Power BI新人快速上手手册
· 适用人群:数据分析专业人士,在数据分析方向需求发展人士 · 应用场景:数据汇报.数据可视化展现.数据建模分析 · 掌握难度:★★★★☆ 本期讲师 『PowerPivot工坊』公众号提供Power ...
- selenium +python之多线程与多进程应用于自动化测试
多线程与多进程与自动化测试用例结合起来执行,从而节省测试用例的总体运行时间. 多线程执行测试测试用例 以百度搜索为例,通过不同的浏览器来启动不同的线程. from selenium import we ...
- PostgreSQL缓存
目录[-] pg_buffercache pgfincore pg_prewarm dstat Linux ftools 使用pg_prewarm预加载关系/索引: pgfincore 输出: 怎样刷 ...
- lca(最近公共祖先(在线)) 倍增法详解
转自大佬博客 : https://blog.csdn.net/lw277232240/article/details/72870644 描述:倍增法用于很多算法当中,通过字面意思来理解 LCA是啥呢 ...