C# 递归地获取属性&;类的子属性

C# 递归地获取属性&;类的子属性,c#,reflection,recursion,C#,Reflection,Recursion,我在做类似的事情,但我想递归地使用反射来获得每个属性。我从你那里得到了密码 代码的问题是:它只下降了一级,我想知道如何使用反射自动获取所有属性?我刚刚编写了以下示例容器代码: public class Container { public Bottle MyBottle { get; set; } public List<Address> Addresses { get; set; } public Container() { Add

我在做类似的事情,但我想递归地使用反射来获得每个属性。我从你那里得到了密码

代码的问题是:它只下降了一级,我想知道如何使用反射自动获取所有属性?我刚刚编写了以下示例容器代码:

public class Container
{
    public Bottle MyBottle { get; set; }
    public List<Address> Addresses { get; set; }

    public Container()
    {
        Address a = new Address();
        a.AddressLine1 = "1 Main St";
        a.AddressLine2 = "2 Main St";
        Addresses = new List<Address>();
        Addresses.Add(a);

        MyBottle = new Bottle();
        MyBottle.BottleName = "Big bottle";
        MyBottle.BottageAge = 2;
    }
}

public class Bottle
{
    public string BottleName { get; set; }
    public int BottageAge { get; set; }
}

public class Address
{
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public List<SpecialFolder> SpecialFolders { get; set; }

    public Address()
    {
        SpecialFolders = new List<SpecialFolder>();
        SpecialFolder sf = new SpecialFolder();
        sf.TemplateFolder = Environment.SpecialFolder.Templates.ToString();
        sf.UserFolder = Environment.SpecialFolder.UserProfile.ToString();
        SpecialFolders.Add(sf);
    }
}

public class SpecialFolder
{
    public string TemplateFolder { get; set; }
    public string UserFolder { get; set; }
}
我希望得到:

MyBottle:
      BottleName: Big bottle
      BottageAge: 2
Addresses:
      AddressLine1: 1 Main St
      AddressLine2: 2 Main St
      SpecialFolders:
            TemplateFolder: Templates
            UserFolder: UserProfile
我现在得到的结果是:

MyBottle:
  BottleName: Big bottle
  BottageAge: 2
Addresses: System.Collections.Generic.List`1[TreeViewReflectionExample.Address]

有人能帮我使用PrintProperties方法吗?非常感谢。

您的代码有两个问题:

  • 由于条件
    if(property.PropertyType.Assembly==objType.Assembly)
    的原因,您将省略
    System.Collections
    like
    List
  • 对于属于集合的
    propValue
    ,您没有区别对待。因此,它将打印
    列表
    属性,而不是其元素属性 例如,您可以将其更改为:

    public void PrintProperties(object obj, int indent)
    {    
        if (obj == null) return;
        string indentString = new string(' ', indent);
        Type objType = obj.GetType();
        PropertyInfo[] properties = objType.GetProperties();
        foreach (PropertyInfo property in properties)
        {
            object propValue = property.GetValue(obj, null);
            var elems = propValue as IList;
            if (elems != null)
            {
                foreach (var item in elems)
                {
                    PrintProperties(item, indent + 3);
                }
            }
            else
            {
                // This will not cut-off System.Collections because of the first check
                if (property.PropertyType.Assembly == objType.Assembly)
                {
                    Console.WriteLine("{0}{1}:", indentString, property.Name);
    
                    PrintProperties(propValue, indent + 2);
                }
                else
                {
                    Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
                }
            }
        }
    }
    

    您希望分别处理基元类型和字符串,并在可枚举项上循环,而不只是获取它们的ToString()值。因此,您的代码可以更新为:

    public void PrintProperties(object obj, int indent)
    {
    
        if (obj == null) return;
        string indentString = new string(' ', indent);
        Type objType = obj.GetType();
        PropertyInfo[] properties = objType.GetProperties();
        foreach (PropertyInfo property in properties)
        {   
            object propValue = property.GetValue(obj, null);
            if(property.PropertyType.IsPrimitive || property.PropertyType == typeof(string))
                Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
            else if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
            {
                Console.WriteLine("{0}{1}:", indentString, property.Name);
                IEnumerable enumerable = (IEnumerable)propValue;
                foreach(object child in enumerable)
                    PrintProperties(child, indent + 2);
            }
            else 
            {
                Console.WriteLine("{0}{1}:", indentString, property.Name);
                PrintProperties(propValue, indent + 2);
            }
        }
    }
    

    它适用于除propValue为string[]之外的所有情况。您将在第行中看到异常“参数计数不匹配”: object propValue=property.GetValue(obj,null)

    要解决此问题,您可以使用此代码进行一些修复:

    private void PrintProperties(object obj, int indent)
        {
            if (obj == null) return;
            string indentString = new string(' ', indent);
            Type objType = obj.GetType();
            PropertyInfo[] properties = objType.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                object propValue = property.GetValue(obj, null);
    
                var elems = propValue as IList;
                if ((elems != null) && !(elems is string[]) )
                {
                    foreach (var item in elems)
                    {
                        PrintProperties(item, indent + 3);
                    }
                }
                else
                {
                    // This will not cut-off System.Collections because of the first check
                    if (property.PropertyType.Assembly == objType.Assembly)
                    {
                        LogToWindow(String.Format("{0}{1}:", indentString, property.Name));
                        PrintProperties(propValue, indent + 2);
                    }
                    else
                    {
                        if (propValue is string[])
                        {
                            var str = new StringBuilder();
                            foreach (string item in (string[])propValue)
                            {
                                str.AppendFormat("{0}; ", item);
                            }
                            propValue = str.ToString();
                            str.Clear();
                        }
                        LogToWindow(String.Format("{0}{1}: {2}", indentString, property.Name, propValue));
                    }
                }
            }
        }
    

    根据Konrad Kokosa的回答:

    private string ObjectToString(object obj, int indent = 0)
    {
        if (obj is null)
        {
            return "";
        }
    
        var sb = new StringBuilder();
        string indentString = new string(' ', indent);
        Type objType = obj.GetType();
    
        foreach (PropertyInfo property in objType.GetProperties())
        {
            object propValue = property.GetValue(obj);
            var elems = propValue as IList;
    
            if (elems != null)
            {
                foreach (var item in elems)
                {
                    sb.Append($"{indentString}- {property.Name}\n");
                    sb.Append(ObjectToString(item, indent + 4));
                }
            }
            else if (property.Name != "ExtensionData")
            {
                sb.Append($"{indentString}- {property.Name}={propValue}\n");
    
                if (property.PropertyType.Assembly == objType.Assembly)
                {
                    sb.Append(ObjectToString(propValue, indent + 4));
                }
            }
        }
    
        return sb.ToString();
    }
    
    更新

    根据此旧问题编辑代码:

    私有字符串ObjectToString(objectobj,int indent=0)
    {
    var sb=新的StringBuilder();
    如果(obj!=null)
    {
    字符串缩进字符串=新字符串(“”,缩进);
    if(obj是字符串)
    {
    sb.Append($“{indentString}-{obj}\n”);
    }
    else if(对象是数组)
    {
    var elems=作为IList的obj;
    sb.Append($“{indentString}-[{elems.Count}]:\n”);
    for(int i=0;i
    更新2

    public static string ObjectToString(object obj, int indent = 0)
        {
            var sb = new StringBuilder();
    
            if (obj != null)
            {
                string indentString = new string(' ', indent);
    
                if (obj is string || obj.IsNumber())
                {
                    sb.Append($"{indentString}- {obj}\n");
                }
                else if (obj.GetType().BaseType == typeof(Enum))
                {
                    sb.Append($"{indentString}- {obj.ToString()}\n");
                }
                else if (obj is Array)
                {
                    var elems = obj as IList;
                    sb.Append($"{indentString}- [{elems.Count}] :\n");
    
                    for (int i = 0; i < elems.Count; i++)
                    {
                        sb.Append(ObjectToString(elems[i], indent + 4));
                    }
                }
                else
                {
                    Type objType = obj.GetType();
                    PropertyInfo[] props = objType.GetProperties();
    
                    foreach (PropertyInfo prop in props)
                    {
                        if (prop.GetIndexParameters().Length == 0)
                        {
                            object propValue = prop.GetValue(obj);
                            var elems = propValue as IList;
    
                            if (elems != null)
                            {
                                foreach (var item in elems)
                                {
                                    sb.Append($"{indentString}- {prop.Name} :\n");
                                    sb.Append(ObjectToString(item, indent + 4));
                                }
                            }
                            else if (prop.Name != "ExtensionData")
                            {
                                sb.Append($"{indentString}- {prop.Name} = {propValue}\n");
    
                                if (prop.PropertyType.Assembly == objType.Assembly)
                                {
                                    sb.Append(ObjectToString(propValue, indent + 4));
                                }
                            }
                        }
                        else if (objType.GetProperty("Item") != null)
                        {
                            int count = -1;
    
                            if (objType.GetProperty("Count") != null &&
                                objType.GetProperty("Count").PropertyType == typeof(int))
                            {
                                count = (int)objType.GetProperty("Count").GetValue(obj, null);
                            }
    
                            for (int i = 0; i < count; i++)
                            {
                                object val = prop.GetValue(obj, new object[] { i });
                                sb.Append(ObjectToString(val, indent + 4));
                            }
                        }
                    }
                }
            }
    
            return sb.ToString();
        }
    
        public static bool IsNumber(this object value)
        {
            return value is sbyte
                || value is byte
                || value is short
                || value is ushort
                || value is int
                || value is uint
                || value is long
                || value is ulong
                || value is float
                || value is double
                || value is decimal;
        }
    
    public静态字符串ObjectToString(objectobj,int indent=0)
    {
    var sb=新的StringBuilder();
    如果(obj!=null)
    {
    字符串缩进字符串=新字符串(“”,缩进);
    if(obj是字符串| | obj.IsNumber())
    {
    sb.Append($“{indentString}-{obj}\n”);
    }
    else if(obj.GetType().BaseType==typeof(Enum))
    {
    sb.Append($“{indentString}-{obj.ToString()}\n”);
    }
    else if(对象是数组)
    {
    var elems=作为IList的obj;
    sb.Append($“{indentString}-[{elems.Count}]:\n”);
    for(int i=0;iprivate string ObjectToString(object obj, int indent = 0)
        {
            var sb = new StringBuilder();
    
            if (obj != null)
            {
                string indentString = new string(' ', indent);
    
                if (obj is string)
                {
                    sb.Append($"{indentString}- {obj}\n");
                }
                else if (obj is Array)
                {
                    var elems = obj as IList;
                    sb.Append($"{indentString}- [{elems.Count}] :\n");
    
                    for (int i = 0; i < elems.Count; i++)
                    {
                        sb.Append(ObjectToString(elems[i], indent + 4));
                    }
                }
                else
                {
                    Type objType = obj.GetType();
                    PropertyInfo[] props = objType.GetProperties();
    
                    foreach (PropertyInfo prop in props)
                    {
                        if (prop.GetIndexParameters().Length == 0)
                        {
                            object propValue = prop.GetValue(obj);
                            var elems = propValue as IList;
    
                            if (elems != null)
                            {
                                foreach (var item in elems)
                                {
                                    sb.Append($"{indentString}- {prop.Name} :\n");
                                    sb.Append(ObjectToString(item, indent + 4));
                                }
                            }
                            else if (prop.Name != "ExtensionData")
                            {
                                sb.Append($"{indentString}- {prop.Name} = {propValue}\n");
    
                                if (prop.PropertyType.Assembly == objType.Assembly)
                                {
                                    sb.Append(ObjectToString(propValue, indent + 4));
                                }
                            }
                        }
                        else
                        {
                            sb.Append($"{indentString}- {prop.Name} ({prop.PropertyType.Name}): <Indexed>\n");
                        }
                    }
                }
            }
    
            return sb.ToString();
        }
    
    public static string ObjectToString(object obj, int indent = 0)
        {
            var sb = new StringBuilder();
    
            if (obj != null)
            {
                string indentString = new string(' ', indent);
    
                if (obj is string || obj.IsNumber())
                {
                    sb.Append($"{indentString}- {obj}\n");
                }
                else if (obj.GetType().BaseType == typeof(Enum))
                {
                    sb.Append($"{indentString}- {obj.ToString()}\n");
                }
                else if (obj is Array)
                {
                    var elems = obj as IList;
                    sb.Append($"{indentString}- [{elems.Count}] :\n");
    
                    for (int i = 0; i < elems.Count; i++)
                    {
                        sb.Append(ObjectToString(elems[i], indent + 4));
                    }
                }
                else
                {
                    Type objType = obj.GetType();
                    PropertyInfo[] props = objType.GetProperties();
    
                    foreach (PropertyInfo prop in props)
                    {
                        if (prop.GetIndexParameters().Length == 0)
                        {
                            object propValue = prop.GetValue(obj);
                            var elems = propValue as IList;
    
                            if (elems != null)
                            {
                                foreach (var item in elems)
                                {
                                    sb.Append($"{indentString}- {prop.Name} :\n");
                                    sb.Append(ObjectToString(item, indent + 4));
                                }
                            }
                            else if (prop.Name != "ExtensionData")
                            {
                                sb.Append($"{indentString}- {prop.Name} = {propValue}\n");
    
                                if (prop.PropertyType.Assembly == objType.Assembly)
                                {
                                    sb.Append(ObjectToString(propValue, indent + 4));
                                }
                            }
                        }
                        else if (objType.GetProperty("Item") != null)
                        {
                            int count = -1;
    
                            if (objType.GetProperty("Count") != null &&
                                objType.GetProperty("Count").PropertyType == typeof(int))
                            {
                                count = (int)objType.GetProperty("Count").GetValue(obj, null);
                            }
    
                            for (int i = 0; i < count; i++)
                            {
                                object val = prop.GetValue(obj, new object[] { i });
                                sb.Append(ObjectToString(val, indent + 4));
                            }
                        }
                    }
                }
            }
    
            return sb.ToString();
        }
    
        public static bool IsNumber(this object value)
        {
            return value is sbyte
                || value is byte
                || value is short
                || value is ushort
                || value is int
                || value is uint
                || value is long
                || value is ulong
                || value is float
                || value is double
                || value is decimal;
        }