Reputation: 273
I am using reflection to get a class name, and need to get all sub properties of the class, and all the sub properties' properties.
I am running into a recursion issue where the items get added to the incorrect list.
My code is as follows:
private List<Member> GetMembers(object instance)
{
var memberList = new List<Member>();
var childMembers = new List<Member>();
foreach (var propertyInfo in instance.GetType().GetProperties())
{
var member = new Member
{
Name = propertyInfo.PropertyType.IsList() ? propertyInfo.Name + "[]" : propertyInfo.Name,
Type = SetPropertyType(propertyInfo.PropertyType),
};
if (propertyInfo.PropertyType.IsEnum)
{
member.Members = GetEnumValues(propertyInfo).ToArray();
}
if (propertyInfo.PropertyType.BaseType == typeof(ModelBase))
{
var childInstance = propertyInfo.GetValue(instance) ?? Activator.CreateInstance(propertyInfo.PropertyType);
childMembers.AddRange(GetMembers(childInstance));
member.Members = childMembers.ToArray();
}
if (propertyInfo.PropertyType.IsGenericType && (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>) ||
propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
{
var itemType = propertyInfo.PropertyType.GetGenericArguments()[0];
var childInstance = Activator.CreateInstance(itemType);
childMembers.AddRange(GetMembers(childInstance));
member.Members = childMembers.Distinct().ToArray();
}
memberList.Add(member);
}
return memberList;
}
Upvotes: 0
Views: 664
Reputation: 2857
I can't know for certain since I don't have the knowledge of your code to debug and test it; however, I believe your problem may be stemming from the fact that you're re-using the childMembers
list. Let me know if this is not the case.
private List<Member> GetMembers(object instance)
{
var memberList = new List<Member>();
foreach (var propertyInfo in instance.GetType().GetProperties())
{
var childMembers = new List<Member>(); // Moved to here, so it's not shared among all propertyInfo iterations.
var member = new Member
{
Name = propertyInfo.PropertyType.IsList() ? propertyInfo.Name + "[]" : propertyInfo.Name,
Type = SetPropertyType(propertyInfo.PropertyType),
};
if (propertyInfo.PropertyType.IsEnum)
{
member.Members = GetEnumValues(propertyInfo).ToArray();
}
if (propertyInfo.PropertyType.BaseType == typeof(ModelBase))
{
var childInstance = propertyInfo.GetValue(instance) ?? Activator.CreateInstance(propertyInfo.PropertyType);
childMembers.AddRange(GetMembers(childInstance));
member.Members = childMembers.ToArray();
}
if (propertyInfo.PropertyType.IsGenericType && (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>) ||
propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
{
var itemType = propertyInfo.PropertyType.GetGenericArguments()[0];
var childInstance = Activator.CreateInstance(itemType);
childMembers.AddRange(GetMembers(childInstance));
member.Members = childMembers.Distinct().ToArray();
}
memberList.Add(member);
}
return memberList;
}
Upvotes: 1
Reputation: 32740
Wouldn't the following do?
public static IEnumerable<PropertyInfo> GetProperties(this Type type, int depth = 1)
{
IEnumerable<PropertyInfo> getProperties(Type currentType, int currentDepth)
{
if (currentDepth >= depth)
yield break;
foreach (var property in currentType.GetProperties())
{
yield return property;
foreach (var subProperty in getProperties(property.PropertyType,
currentDepth + 1))
{
yield return subProperty;
}
}
}
if (depth < 1)
throw new ArgumentOutOfRangeException(nameof(depth));
return getProperties(type, 0);
}
Given the following type:
class Foo
{
public string S { get; }
public int I { get; }
}
The output of
Console.WriteLine(string.Join(Environment.NewLine,
typeof(Foo).GetProperties(2)
.Select(p => $"{p.DeclaringType.Name}: {p.Name}")));
would be:
Foo: S
String: Chars
String: Length
Foo: I
Upvotes: 0