.NET反射API不提供“无视枚举属性控制”或“继承快照导出”的开箱即用功能,需组合BindingFlags、递归遍历BaseType/GetInterfaces并投影到DTO实现结构化快照。

直接说结论:.NET 内置反射 API 本身不提供“无视枚举属性控制”或“继承快照导出”的开箱即用功能。所谓“彻底审计”“继承快照”,是业务需求描述,不是反射 API 的标准能力。要实现这类目标,需组合使用反射基础能力,并主动绕过(或忽略)某些访问限制——但必须清楚边界与代价。
反射能拿到什么:类型结构、成员、继承链、自定义特性
System.Reflection 提供的核心能力包括:
-
Type.GetInterfaces()、Type.BaseType获取继承关系 -
Type.GetFields()、GetProperties()、GetMethods()列出成员(默认只返回 public) - 加上
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static可访问 private / protected 成员 -
Attribute.GetCustomAttributes()提取[Serializable]、[Obsolete]等元数据 -
Type.IsEnum、Enum.GetNames()、Enum.GetValues()支持枚举本身分析
但注意:枚举的“属性控制”(如 [Browsable(false)]、[EditorBrowsable(EditorBrowsableState.Never)])只是设计时提示,不影响反射读取——反射始终能获取所有字段(包括 underlying value),这些属性不阻止 GetFields(BindingFlags.Public | BindingFlags.NonPublic) 返回枚举项。
“无视枚举属性控制”的实际含义与操作
如果你指的是“不管有没有 [Browsable] 或 [JsonIgnore],都要把所有枚举值及其元数据拉出来”,那很简单:
- 枚举本质是带命名常量的整数类型,反射不看装饰属性,只看 IL 定义
- 正确做法是:
- 用
typeof(MyEnum).GetFields(BindingFlags.Public | BindingFlags.Static)获取所有命名字段 - 对每个
FieldInfo调用field.GetValue(null)得值,field.GetCustomAttributes()拿属性 - 不需要特殊配置或绕过机制——它本来就不受那些 UI/序列化属性约束
- 用
常见误区:把 [JsonIgnore] 当作反射屏障,其实它只影响 System.Text.Json 或 Newtonsoft.Json 序列化器,和 GetFields() 完全无关。
“继承快照”的实现逻辑:递归遍历类型层级
要导出一个类型完整的“继承快照”(含基类、接口、各层字段/属性/方法),需手动展开:
- 从目标类型开始,沿
BaseType向上直到null(Object 为止) - 对每一层调用
GetMembers(BindingFlags.DeclaredOnly | ...)避免重复继承成员 - 同时用
GetInterfaces()收集全部接口(包括间接实现的,需递归GetInterfaces()) - 每个成员记录:名称、类型、可访问性、是否重写、是否显式接口实现、关联特性
示例关键代码片段:
var snapshot = new List<MemberSnapshot>();
for (Type t = targetType; t != null; t = t.BaseType)
{
foreach (var member in t.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
{
snapshot.Add(new MemberSnapshot
{
DeclaringType = t.FullName,
Name = member.Name,
MemberType = member.MemberType.ToString(),
IsInherited = t != targetType
});
}
}导出为结构化数据:JSON 或 CSV 即可,无需额外框架
- 用
System.Text.Json.JsonSerializer.Serialize(snapshot, new JsonSerializerOptions { WriteIndented = true })直接转 JSON - 若需 Excel 兼容,用 CSV:每行字段为
DeclaringType,Name,MemberType,IsInherited,Attributes,属性列表用|分隔 - 注意:
MemberInfo不能直接序列化,需投影到 DTO 类(如MemberSnapshot),避免NotSupportedException
不复杂但容易忽略:反射结果不含运行时值(除非你实例化对象并调用 getter),所谓“快照”是编译时结构快照,不是内存状态快照。

















