使用反射获取类的所有属性及子属性时遇递归问题求助
解决反射递归获取属性时的列表归属问题
我懂你现在的困扰——递归遍历嵌套属性的时候,子成员总是跑到错误的列表里,导致整个结构乱掉对吧?看你贴的代码片段,应该是递归调用GetMembers时没有把子属性正确关联到父成员的子集合里,而是一股脑加到了顶层列表或者某个共用的子列表中。
先明确核心前提
你的Member类应该需要一个存放子成员的属性,不然没法区分层级,比如:
public class Member { public string Name { get; set; } public object Value { get; set; } public List<Member> ChildMembers { get; set; } = new List<Member>(); // 关键:子成员专属容器 }
之前的代码里,你可能把递归获取到的子成员都塞到了同一个childMembers列表,没有绑定到当前遍历的父member上,自然会出现层级混乱的问题。
修正后的递归实现
下面是调整后的代码,重点解决递归时的列表归属问题,同时处理了值类型、字符串和循环引用的边界情况:
private List<Member> GetMembers(object instance, HashSet<object> processedObjects = null) { var memberList = new List<Member>(); // 初始化已处理对象集合,防止循环引用导致栈溢出 processedObjects ??= new HashSet<object>(); // 边界处理:值类型、字符串、null或已处理过的对象,直接返回空列表(按需调整) if (instance == null || instance.GetType().IsValueType || instance is string || processedObjects.Contains(instance)) { return memberList; } processedObjects.Add(instance); var type = instance.GetType(); foreach (var propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { // 跳过索引器属性(比如this[int index]这类) if (propertyInfo.GetIndexParameters().Length > 0) continue; var member = new Member { Name = propertyInfo.Name, Value = propertyInfo.GetValue(instance) }; // 核心:递归获取当前属性的子成员,直接绑定到当前member的ChildMembers var childMembers = GetMembers(member.Value, processedObjects); member.ChildMembers.AddRange(childMembers); memberList.Add(member); } return memberList; }
关键调整点
- 子成员归属正确:递归得到的子成员直接添加到当前
member的ChildMembers,而不是共用的列表,保证层级结构清晰。 - 循环引用防护:用
HashSet<object>跟踪已经处理过的对象,避免对象互相引用导致无限递归栈溢出。 - 边界类型过滤:跳过值类型、字符串和null,因为这些没有子属性可遍历。
- 排除索引器:去掉类里的索引器属性,避免不必要的无效遍历。
调用示例验证
假设你有这样的嵌套类:
public class Address { public string Street { get; set; } public string City { get; set; } } public class User { public string Name { get; set; } public int Age { get; set; } public Address HomeAddress { get; set; } }
调用GetMembers(new User { Name = "John", Age = 30, HomeAddress = new Address { Street = "Main St", City = "NY" } }),就能得到正确的层级结构:
- User
- Name: "John"
- Age: 30
- HomeAddress
- Street: "Main St"
- City: "NY"
这样就不会出现子成员跑到错误列表的问题啦!
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

