Je faisais quelque chose comme Obtenir récursivement les propriétés et les propriétés enfants d'un objet , mais je voulais utiliser la réflexion de manière récursive pour obtenir chaque propriété. Et j'ai eu le code de Imprimer récursivement les propriétés .
Le problème avec le code est: il ne descend que d'un niveau, je me demande comment obtenir automatiquement toutes les propriétés en utilisant la réflexion? Je viens de créer l'exemple de code conteneur suivant:
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; }
}
Dans la méthode principale:
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);
}
}
}
J'espère avoir:
MyBottle:
BottleName: Big bottle
BottageAge: 2
Addresses:
AddressLine1: 1 Main St
AddressLine2: 2 Main St
SpecialFolders:
TemplateFolder: Templates
UserFolder: UserProfile
Le résultat que j'obtiens maintenant:
MyBottle:
BottleName: Big bottle
BottageAge: 2
Addresses: System.Collections.Generic.List`1[TreeViewReflectionExample.Address]
Quelqu'un peut-il m'aider avec la méthode PrintProperties? Merci beaucoup.
Vous avez deux problèmes avec votre code:
if (property.PropertyType.Assembly == objType.Assembly)
vous omettez System.Collections
comme List<>
propValue
qui sont des collections. Par conséquent, il imprimera les propriétés List
et non ses propriétés d'éléments. Vous pouvez changer cela par exemple en:
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);
}
}
}
}
Vous souhaitez gérer les types primitifs et les chaînes séparément, et effectuer une boucle sur les énumérables au lieu de simplement prendre leur valeur ToString (). Donc, votre code pourrait être mis à jour pour:
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);
}
}
}
Cela fonctionne dans tous les cas sauf propValue est string []. Vous obtiendrez l'exception "incompatibilité de comptage de paramètres" en ligne: objet propValue = property.GetValue (obj, null);
Pour résoudre ce problème, vous pouvez utiliser ce code avec un petit correctif:
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));
}
}
}
}