递归获取类的属性和子属性

我正在做一些像递归获取对象的属性和子属性的东西,但我想递归地使用reflection来获取每个属性。 我从Recursively打印属性的代码。

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

public class Container { public Bottle MyBottle { get; set; } public List
Addresses { get; set; } public Container() { Address a = new Address(); a.AddressLine1 = "1 Main St"; a.AddressLine2 = "2 Main St"; Addresses = new List
(); 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 SpecialFolders { get; set; } public Address() { SpecialFolders = new List(); 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; } }

在Main方法中:

 static void Main(string[] args) { Container c = new Container(); PrintProperties(c); } public static void PrintProperties(object obj) { PrintProperties(obj, 0); } public static 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.Assembly == objType.Assembly) { Console.WriteLine("{0}{1}:", indentString, property.Name); PrintProperties(propValue, indent + 2); } else { Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue); } } } 

我希望得到:

 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方法吗? 非常感谢你。

您的代码有两个问题:

  1. 因为条件if (property.PropertyType.Assembly == objType.Assembly)你将省略像List<>这样的System.Collections
  2. 你不要将不同的propValue集合。 因此,它将打印List属性,而不是其元素属性。

您可以将其更改为:

 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 []之外,它适用于所有情况。 您将在行中获得exception“参数计数不匹配”: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)); } } } } 

我改变了驾驶员的代码。 这个对我有用。

 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 (IsSimpleType(property.PropertyType)) { Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue); } else if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType)) { if (property.PropertyType == typeof(string[])) { Console.WriteLine("{0}{1}: {2}", indentString, property.Name, string.Join(",", (string[])propValue)); } else { 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); } } } public static bool IsSimpleType(Type type) { return type.IsValueType || type.IsPrimitive || new Type[] { typeof(String), typeof(Decimal), typeof(DateTime), typeof(DateTimeOffset), typeof(TimeSpan), typeof(Guid) }.Contains(type) || Convert.GetTypeCode(type) != TypeCode.Object; }