Ottieni ricorsivamente proprietà e proprietà figlio di una class

Stavo facendo qualcosa come Recursively Ottieni proprietà e Proprietà figlio di un object , ma volevo usare la riflessione in modo ricorsivo per ottenere ciascuna proprietà. E ho ricevuto il codice da Stampa ricorsiva delle proprietà .

Il problema con il codice è: scende solo di un livello, mi chiedo come si possano ottenere automaticamente tutte le proprietà usando la riflessione? Ho appena creato il seguente codice del contenitore di esempio:

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

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

Spero di ottenere:

 MyBottle: BottleName: Big bottle BottageAge: 2 Addresses: AddressLine1: 1 Main St AddressLine2: 2 Main St SpecialFolders: TemplateFolder: Templates UserFolder: UserProfile 

Il risultato che ottengo ora:

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

Qualcuno può aiutarmi con il metodo PrintProperties? Grazie mille.

Hai due problemi con il tuo codice:

  1. a causa della condizione if (property.PropertyType.Assembly == objType.Assembly) omettete System.Collections come List<>
  2. tu non tratti diversamente propValue che sono raccolte. Quindi stamperà le proprietà della List , non le proprietà degli elementi.

Puoi cambiarlo ad esempio in:

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

Si desidera gestire separatamente i tipi e le stringhe primitivi e ripetere il ciclo su enumerabili anziché prendere semplicemente il loro valore ToString (). Quindi il tuo codice potrebbe essere aggiornato a:

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

Funziona per tutti i casi tranne che PropValue è una stringa []. Otterrete l’eccezione “Parameter Count Mismatch” in linea: object propValue = property.GetValue (obj, null);

Per risolvere questo problema puoi usare questo codice con una piccola correzione:

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

Ho cambiato il codice di driis qui sotto. Per me funziona.

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