从类中获取所有属性和子属性

时间:2018-04-30 12:58:19

标签: c# reflection

我使用反射来获取类名,并且需要获取类的所有子属性以及所有子属性'属性。

我遇到了一个递归问题,其中的项目被添加到错误的列表中。

我的代码如下:

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;
}

2 个答案:

答案 0 :(得分:1)

我无法确定,因为我没有您的代码知识来调试和测试它;但是,我相信您的问题可能源于您重新使用childMembers列表的事实。如果情况不是这样,请告诉我。

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;
}

答案 1 :(得分:0)

以下不会吗?

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);    
}

给出以下类型:

class Foo
{
    public string S { get; }
    public int I { get; }
}

的输出
Console.WriteLine(string.Join(Environment.NewLine,
                  typeof(Foo).GetProperties(2)
                             .Select(p => $"{p.DeclaringType.Name}: {p.Name}")));

将是:

Foo: S
String: Chars
String: Length
Foo: I