Existe-t-il une méthode intégrée à .NET capable d’écrire toutes les propriétés d’un object sur la console? Pourrait en faire une en utilisant la reflection bien sûr, mais je suis curieux de savoir si cela existe déjà … surtout depuis que vous pouvez le faire dans Visual Studio dans la fenêtre immédiate. Vous pouvez y trouver un nom d’object (en mode débogage), appuyez sur Entrée, et il est imprimé de manière assez élégante avec tous ses éléments.
Une méthode comme celle-ci existe-t-elle?
La classe ObjectDumper est connue pour faire cela. Je n’ai jamais confirmé, mais j’ai toujours soupçonné que la fenêtre immédiate utilise ça.
EDIT: Je viens de me rendre compte que le code pour ObjectDumper est en fait sur votre machine. Aller à:
c: / Program Files / Microsoft Visual Studio 9.0 / Exemples / 1033 / CSharpSamples.zip
Cela va décompresser dans un dossier appelé LinqSamples. Ici, il y a un projet appelé ObjectDumper. Utiliser ça.
(Cela rendra aussi David dans les commentaires heureux :))
Pour ce faire, vous pouvez utiliser la classe TypeDescriptor :
foreach(PropertyDescriptor descriptor in TypeDescriptor.GetProperties(obj)) { ssortingng name=descriptor.Name; object value=descriptor.GetValue(obj); Console.WriteLine("{0}={1}",name,value); }
TypeDescriptor réside dans l’espace de noms System.ComponentModel et est l’API utilisée par Visual Studio pour afficher votre object dans son navigateur de propriétés. Il est finalement basé sur la reflection (comme n’importe quelle solution), mais il fournit un assez bon niveau d’abstraction de l’API de reflection.
Basé sur ObjectDumper des exemples LINQ, j’ai créé une version qui vide chacune des propriétés sur sa propre ligne.
Cet exemple de classe
namespace MyNamespace { public class User { public ssortingng FirstName { get; set; } public ssortingng LastName { get; set; } public Address Address { get; set; } public IList Hobbies { get; set; } } public class Hobby { public ssortingng Name { get; set; } } public class Address { public ssortingng Street { get; set; } public int ZipCode { get; set; } public ssortingng City { get; set; } } }
a une sortie de
{MyNamespace.User} FirstName: "Arnold" LastName: "Schwarzenegger" Address: { } {MyNamespace.Address} Street: "6834 Hollywood Blvd" ZipCode: 90028 City: "Hollywood" Hobbies: ... {MyNamespace.Hobby} Name: "body building"
Voici le code
using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Text; public class ObjectDumper { private int _level; private readonly int _indentSize; private readonly SsortingngBuilder _ssortingngBuilder; private readonly List _hashListOfFoundElements; private ObjectDumper(int indentSize) { _indentSize = indentSize; _ssortingngBuilder = new SsortingngBuilder(); _hashListOfFoundElements = new List (); } public static ssortingng Dump(object element) { return Dump(element, 2); } public static ssortingng Dump(object element, int indentSize) { var instance = new ObjectDumper(indentSize); return instance.DumpElement(element); } private ssortingng DumpElement(object element) { if (element == null || element is ValueType || element is ssortingng) { Write(FormatValue(element)); } else { var objectType = element.GetType(); if (!typeof(IEnumerable).IsAssignableFrom(objectType)) { Write("{{{0}}}", objectType.FullName); _hashListOfFoundElements.Add(element.GetHashCode()); _level++; } var enumerableElement = element as IEnumerable; if (enumerableElement != null) { foreach (object item in enumerableElement) { if (item is IEnumerable && !(item is ssortingng)) { _level++; DumpElement(item); _level--; } else { if (!AlreadyTouched(item)) DumpElement(item); else Write("{{{0}}} <-- bidirectional reference found", item.GetType().FullName); } } } else { MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance); foreach (var memberInfo in members) { var fieldInfo = memberInfo as FieldInfo; var propertyInfo = memberInfo as PropertyInfo; if (fieldInfo == null && propertyInfo == null) continue; var type = fieldInfo != null ? fieldInfo.FieldType : propertyInfo.PropertyType; object value = fieldInfo != null ? fieldInfo.GetValue(element) : propertyInfo.GetValue(element, null); if (type.IsValueType || type == typeof(string)) { Write("{0}: {1}", memberInfo.Name, FormatValue(value)); } else { var isEnumerable = typeof(IEnumerable).IsAssignableFrom(type); Write("{0}: {1}", memberInfo.Name, isEnumerable ? "..." : "{ }"); var alreadyTouched = !isEnumerable && AlreadyTouched(value); _level++; if (!alreadyTouched) DumpElement(value); else Write("{{{0}}} <-- bidirectional reference found", value.GetType().FullName); _level--; } } } if (!typeof(IEnumerable).IsAssignableFrom(objectType)) { _level--; } } return _stringBuilder.ToString(); } private bool AlreadyTouched(object value) { if (value == null) return false; var hash = value.GetHashCode(); for (var i = 0; i < _hashListOfFoundElements.Count; i++) { if (_hashListOfFoundElements[i] == hash) return true; } return false; } private void Write(string value, params object[] args) { var space = new string(' ', _level * _indentSize); if (args != null) value = string.Format(value, args); _stringBuilder.AppendLine(space + value); } private string FormatValue(object o) { if (o == null) return ("null"); if (o is DateTime) return (((DateTime)o).ToShortDateString()); if (o is string) return string.Format("\"{0}\"", o); if (o is char && (char)o == '\0') return string.Empty; if (o is ValueType) return (o.ToString()); if (o is IEnumerable) return ("..."); return ("{ }"); } }
et vous pouvez l'utiliser comme ça:
var dump = ObjectDumper.Dump(user);
modifier
Peut-être via JavaScriptSerializer.Serialize ?
En ce qui concerne TypeDescriptor de la réponse de Sean (je ne peux pas commenter parce que j’ai une mauvaise réputation), un des avantages de TypeDescriptor par rapport à GetProperties () est que TypeDescriptor a un mécanisme pour attacher dynamicment des propriétés aux objects .
Par exemple, lorsqu’ils travaillent avec PSObject de PowerShell, qui peut avoir des propriétés et des méthodes ajoutées au moment de l’exécution, ils ont implémenté un TypeDescriptor personnalisé qui fusionne ces membres avec le jeu de membres standard. En utilisant TypeDescriptor, votre code n’a pas besoin d’être conscient de ce fait.
Les composants, les contrôles et peut-être que DataSets utilise également cette API.
L’extrait suivant fera la fonction souhaitée:
Type t = obj.GetType();//where obj is object whose properties you need. PropertyInfo [] pi =t.GetProperties(); foreach (PropertyInfo p in pi) { System.Console.WriteLine(p.Name + " " + p.GetType); }
Je pense que si vous écrivez ceci comme méthode d’extension, vous pouvez l’utiliser sur tous les types d’objects.
C’est exactement à quoi sert la reflection. Je ne pense pas qu’il y ait une solution plus simple, mais la reflection n’est pas ce code intensif de toute façon.
Toute autre solution / bibliothèque va au final utiliser la reflection pour introspection du type …
Ne le pense pas. J’ai toujours dû les écrire ou utiliser le travail de quelqu’un d’autre pour obtenir cette information. Doit être reflection à ma connaissance.
MODIFIER:
Vérifiez ceci . J’étais en Mscorlib_CollectionDebugView<>
étudier un débogage sur de longs graphes d’object et je l’ai remarqué lorsque Mscorlib_CollectionDebugView<>
montres, VS dans cette classe: Mscorlib_CollectionDebugView<>
. Il s’agit d’un type interne permettant d’afficher facilement les collections pour les afficher dans les modes de débogage Windows / Windows. Maintenant que c’est interne, vous pouvez le référencer, mais vous pouvez utiliser Reflector pour copier (à partir de mscorlib) le code et avoir le vôtre (le lien ci-dessus contient un exemple de copier / coller). Semble vraiment utile.