Qual è il modo migliore per scaricare interi oggetti su un registro in C #?

Quindi, per vedere lo stato di un object corrente in fase di esecuzione, mi piace molto quello che mi dà la finestra Immediata di Visual Studio. Sto solo facendo un semplice

? objectname 

Mi darà un “dump” ben formattato dell’object.

C’è un modo semplice per farlo in codice, quindi posso fare qualcosa di simile durante la registrazione?

È ansible basare qualcosa sul codice ObjectDumper fornito con gli esempi Linq .
Dai anche un’occhiata alla risposta di questa domanda correlata per ottenere un campione.

Per un grafo di oggetti più grande, io uso l’uso di Json ma con una strategia leggermente diversa. Per prima cosa ho una class statica facile da chiamare e con un metodo statico che avvolge la conversione Json (nota: potrebbe rendere questo un metodo di estensione).

 using Newtonsoft.Json; public static class F { public static string Dump(object obj) { return JsonConvert.SerializeObject(obj); } } 

Quindi nella Immediate Window ,

 var lookHere = F.Dump(myobj); 

lookHere apparirà automaticamente nella finestra dei Locals preceduta da $ o puoi aggiungervi un orologio. Sul lato destro della colonna Value nell’ispettore, c’è una lente d’ingrandimento con accanto un cursore a discesa. Scegli il cursore a discesa e scegli visualizzatore Json.

Screenshot della finestra di Locals 2013 di Visual Studio

Sto usando Visual Studio 2013.

Sono certo che ci sono modi migliori per farlo, ma in passato ho usato un metodo simile al seguente per serializzare un object in una stringa che posso registrare:

  private string ObjectToXml(object output) { string objectAsXmlString; System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(output.GetType()); using (System.IO.StringWriter sw = new System.IO.StringWriter()) { try { xs.Serialize(sw, output); objectAsXmlString = sw.ToString(); } catch (Exception ex) { objectAsXmlString = ex.ToString(); } } return objectAsXmlString; } 

Vedrai che il metodo potrebbe anche restituire l’eccezione piuttosto che l’object serializzato, quindi ti consigliamo di assicurarti che gli oggetti che vuoi registrare siano serializzabili.

Ho un metodo di estensione T.Dump () che fa esattamente questo, dump ricorsivamente tutte le proprietà di qualsiasi tipo in un bel formato leggibile.

Esempio di utilizzo:

 var model = new TestModel(); Console.WriteLine(model.Dump()); 

e uscita:

 { Int: 1, String: One, DateTime: 2010-04-11, Guid: c050437f6fcd46be9b2d0806a0860b3e, EmptyIntList: [], IntList: [ 1, 2, 3 ], StringList: [ one, two, three ], StringIntMap: { a: 1, b: 2, c: 3 } } 

È ansible utilizzare Visual Studio Immediate Window

Basta incollarlo (cambia ovviamente il nome dell’object, ovviamente):

 Newtonsoft.Json.JsonConvert.SerializeObject(actual); 

Dovrebbe stampare object in JSON inserisci la descrizione dell'immagine qui

Dovresti essere in grado di copiarlo su textmechanic text tool o notepad ++ e sostituire le virgolette di escape ( \" ) con " e newline ( \r\n ) con spazio vuoto, quindi rimuovere le doppie virgolette ( " ) dall’inizio e alla fine e incollarlo in jsbeautifier per renderlo più leggibile.

AGGIORNA al commento dell’OP

 public static class Dumper { public static void Dump(this object obj) { Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(obj)); // your logger } } 

questo dovrebbe consentire di scaricare qualsiasi object.

Spero che questo ti salvi un po ‘di tempo.

Ecco un modo stupidamente semplice per scrivere un object piatto, ben formattato:

 using Newtonsoft.Json.Linq; Debug.WriteLine("The object is " + JObject.FromObject(theObjectToDump).ToString()); 

Quello che succede è che l’object viene prima convertito in una rappresentazione interna JSON da JObject.FromObject e quindi convertito in stringa JSON da ToString . (E naturalmente una stringa JSON è una rappresentazione molto bella di un object semplice, specialmente dal momento che ToString includerà newline e rientri.) Il “ToString” è ovviamente estraneo (poiché è implicito usando + per concat una stringa e un object) , ma mi piace specificarlo qui.

È ansible utilizzare la riflessione e il ciclo di tutte le proprietà dell’object, quindi ottenere i relativi valori e salvarli nel registro. La formattazione è davvero banale (potresti usare \ t per indentare proprietà di oggetti e i suoi valori):

 MyObject Property1 = value Property2 = value2 OtherObject OtherProperty = value ... 

Quello che mi piace fare è sovrascrivere ToString () in modo da ottenere un output più utile oltre il nome del tipo. Questo è utile nel debugger, puoi vedere le informazioni che vuoi su un object senza doverlo espandere.

Ho trovato una libreria chiamata ObjectPrinter che consente di scaricare facilmente oggetti e raccolte in stringhe (e altro). Fa esattamente quello di cui avevo bisogno.

Puoi scrivere il tuo metodo WriteLine-

 public static void WriteLine(T obj) { var t = typeof(T); var props = t.GetProperties(); StringBuilder sb = new StringBuilder(); foreach (var item in props) { sb.Append($"{item.Name}:{item.GetValue(obj,null)}; "); } sb.AppendLine(); Console.WriteLine(sb.ToString()); } 

Usalo come-

 WriteLine(myObject); 

Per scrivere una collezione che possiamo usare-

  var ifaces = t.GetInterfaces(); if (ifaces.Any(o => o.Name.StartsWith("ICollection"))) { dynamic lst = t.GetMethod("GetEnumerator").Invoke(obj, null); while (lst.MoveNext()) { WriteLine(lst.Current); } } 

Il metodo può assomigliare-

  public static void WriteLine(T obj) { var t = typeof(T); var ifaces = t.GetInterfaces(); if (ifaces.Any(o => o.Name.StartsWith("ICollection"))) { dynamic lst = t.GetMethod("GetEnumerator").Invoke(obj, null); while (lst.MoveNext()) { WriteLine(lst.Current); } } else if (t.GetProperties().Any()) { var props = t.GetProperties(); StringBuilder sb = new StringBuilder(); foreach (var item in props) { sb.Append($"{item.Name}:{item.GetValue(obj, null)}; "); } sb.AppendLine(); Console.WriteLine(sb.ToString()); } } 

Usando if, else if e controllando le interfacce, gli attributi, il tipo di base, ecc. E la ricorsione (dato che questo è un metodo ricorsivo) in questo modo potremmo ottenere un object dumper, ma è noioso di sicuro. Usando l’object dumper del Microsoft LINQ Sample si risparmia tempo.

Segue un’altra versione che fa la stessa cosa (e gestisce le proprietà annidate), che a mio avviso è più semplice (nessuna dipendenza dalle librerie esterne e può essere facilmente modificata per fare cose diverse dalla registrazione):

 public class ObjectDumper { public static string Dump(object obj) { return new ObjectDumper().DumpObject(obj); } StringBuilder _dumpBuilder = new StringBuilder(); string DumpObject(object obj) { DumpObject(obj, 0); return _dumpBuilder.ToString(); } void DumpObject(object obj, int nestingLevel = 0) { var nestingSpaces = "".PadLeft(nestingLevel * 4); if (obj == null) { _dumpBuilder.AppendFormat("{0}null\n", nestingSpaces); } else if (obj is string || obj.GetType().IsPrimitive) { _dumpBuilder.AppendFormat("{0}{1}\n", nestingSpaces, obj); } else if (ImplementsDictionary(obj.GetType())) { using (var e = ((dynamic)obj).GetEnumerator()) { var enumerator = (IEnumerator)e; while (enumerator.MoveNext()) { dynamic p = enumerator.Current; var key = p.Key; var value = p.Value; _dumpBuilder.AppendFormat("{0}{1} ({2})\n", nestingSpaces, key, value != null ? value.GetType().ToString() : ""); DumpObject(value, nestingLevel + 1); } } } else if (obj is IEnumerable) { foreach (dynamic p in obj as IEnumerable) { DumpObject(p, nestingLevel); } } else { foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(obj)) { string name = descriptor.Name; object value = descriptor.GetValue(obj); _dumpBuilder.AppendFormat("{0}{1} ({2})\n", nestingSpaces, name, value != null ? value.GetType().ToString() : ""); DumpObject(value, nestingLevel + 1); } } } bool ImplementsDictionary(Type t) { return t.GetInterfaces().Any(i => i.Name.Contains("IDictionary")); } }