it-swarm.com.de

Was ist der beste Weg, um ganze Objekte in ein C # -Protokoll zu sichern?

Um also den aktuellen Objektstatus zur Laufzeit anzuzeigen, gefällt mir wirklich, was mir das Visual Studio-Direktfenster bietet. Mach einfach ein einfaches

? objectname

Gibt mir einen schön formatierten "Dump" des Objekts.

Gibt es eine einfache Möglichkeit, dies im Code zu tun, damit ich beim Anmelden etwas Ähnliches tun kann?

115
Dan Esparza

Sie können den ObjectDumper-Code verwenden, der im Lieferumfang von Linq-Beispiele enthalten ist.
Schauen Sie sich auch die Antwort auf diese verwandte Frage an, um eine Probe zu erhalten.

55
Mike Scott

Für eine größere Objektgrafik bin ich der Verwendung von Json gefolgt, aber mit einer etwas anderen Strategie. Zuerst habe ich eine statische Klasse, die einfach aufzurufen ist, und eine statische Methode, die die Json-Konvertierung umschließt (Anmerkung: könnte dies zu einer Erweiterungsmethode machen).

using Newtonsoft.Json;

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

Dann in Ihrem Immediate Window,

var lookHere = F.Dump(myobj);

lookHere wird automatisch im Fenster Locals angezeigt, dem ein $ vorangestellt ist, oder Sie können eine Uhr hinzufügen. Auf der rechten Seite der Spalte Value im Inspektor befindet sich eine Lupe mit einem Dropdown-Cursor. Wählen Sie das Dropdown-Menü und anschließend Json Visualizer.

Screenshot of Visual Studio 2013 Locals window

Ich benutze Visual Studio 2013.

47
Jason

Ich bin mir sicher, dass es dafür bessere Möglichkeiten gibt, aber ich habe in der Vergangenheit eine Methode wie die folgende verwendet, um ein Objekt in eine Zeichenfolge zu serialisieren, die ich protokollieren kann:

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

Sie werden feststellen, dass die Methode möglicherweise auch die Ausnahme und nicht das serialisierte Objekt zurückgibt. Stellen Sie daher sicher, dass die zu protokollierenden Objekte serialisierbar sind.

25

Sie können Visual Studio Immediate Window verwenden

Fügen Sie dies einfach ein (ändern Sie actual offensichtlich in Ihren Objektnamen):

Newtonsoft.Json.JsonConvert.SerializeObject(actual);

Es sollte ein Objekt in JSON drucken enter image description here

Sie sollten in der Lage sein, es zu kopieren über textmechanic text tool oder notepad ++ und maskierte Anführungszeichen zu ersetzen (\") mit " und Zeilenumbrüche (\r\n) mit Leerzeichen, dann doppelte Anführungszeichen entfernen (") vom Anfang bis zum Ende und fügen Sie es in jsbeautifier ein, um die Lesbarkeit zu verbessern.

UPDATE zum Kommentar von OP

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

dies sollte es Ihnen ermöglichen, jedes Objekt zu sichern.

Hoffe das spart dir etwas Zeit.

19

Ich habe eine T.Dump () - Erweiterungsmethode , die genau dies tut und rekursiv alle Eigenschaften eines beliebigen Typs in einem lesbaren Nice-Format ausgibt.

Anwendungsbeispiel:

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

und Ausgabe:

{
    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
    }
}
17
mythz

Hier ist eine dumm einfache Möglichkeit, ein flaches Objekt zu schreiben, das schön formatiert ist:

using Newtonsoft.Json.Linq;

Debug.WriteLine("The object is " + JObject.FromObject(theObjectToDump).ToString());

Das Objekt wird zuerst von JObject.FromObject In eine JSON-interne Darstellung konvertiert und dann von ToString in eine JSON-Zeichenfolge konvertiert. (Und natürlich ist ein JSON-String eine sehr schöne Darstellung eines einfachen Objekts, zumal ToString Zeilenumbrüche und Einrückungen enthält.) Der "ToString" ist natürlich irrelevant (wie es durch die Verwendung von + um einen String und ein Objekt zu verbinden), aber ich möchte es hier irgendwie spezifizieren.

14
Hot Licks

Sie könnten Reflektion verwenden und alle Objekteigenschaften durchlaufen, dann ihre Werte abrufen und sie im Protokoll speichern. Die Formatierung ist wirklich trivial (Sie können\t verwenden, um Objekteigenschaften und ihre Werte einzurücken):

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

Was ich gerne mache, ist das Überschreiben von ToString (), damit ich über den Typnamen hinaus eine nützlichere Ausgabe erhalte. Dies ist praktisch im Debugger. Sie können die gewünschten Informationen zu einem Objekt anzeigen, ohne es erweitern zu müssen.

3
Darryl Braaten

Ich habe eine Bibliothek namens ObjectPrinter gefunden, mit der sich Objekte und Sammlungen einfach in Strings (und mehr) ablegen lassen. Es macht genau das, was ich brauchte.

3

Das Folgende ist eine andere Version, die das Gleiche tut (und verschachtelte Eigenschaften handhabt), was meiner Meinung nach einfacher ist (keine Abhängigkeiten von externen Bibliotheken und kann einfach geändert werden, um andere Aufgaben als die Protokollierung zu erledigen):

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() : "<null>");
                    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() : "<null>");
                DumpObject(value, nestingLevel + 1);
            }
        }
    }

    bool ImplementsDictionary(Type t)
    {
        return t.GetInterfaces().Any(i => i.Name.Contains("IDictionary"));
    }
}
3
engineforce

Basierend auf der @ engineforce-Antwort habe ich diese Klasse erstellt, die ich in einem PCL-Projekt einer Xamarin-Lösung verwende:

/// <summary>
/// Based on: https://stackoverflow.com/a/42264037/6155481
/// </summary>
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)
    {
        var nestingSpaces = "".PadLeft(nestingLevel * 4);

        if (obj == null)
        {
            _dumpBuilder.AppendFormat("{0}null\n", nestingSpaces);
        }
        else if (obj is string || obj.GetType().GetTypeInfo().IsPrimitive || obj.GetType().GetTypeInfo().IsEnum)
        {
            _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() : "<null>");
                    DumpObject(value, nestingLevel + 1);
                }
            }
        }
        else if (obj is IEnumerable)
        {
            foreach (dynamic p in obj as IEnumerable)
            {
                DumpObject(p, nestingLevel);
            }
        }
        else
        {
            foreach (PropertyInfo descriptor in obj.GetType().GetRuntimeProperties())
            {
                string name = descriptor.Name;
                object value = descriptor.GetValue(obj);

                _dumpBuilder.AppendFormat("{0}{1} ({2})\n", nestingSpaces, name, value != null ? value.GetType().ToString() : "<null>");

                // TODO: Prevent recursion due to circular reference
                if (name == "Self" && HasBaseType(obj.GetType(), "NSObject"))
                {
                    // In ObjC I need to break the recursion when I find the Self property
                    // otherwise it will be an infinite recursion
                    Console.WriteLine($"Found Self! {obj.GetType()}");
                }
                else
                {
                    DumpObject(value, nestingLevel + 1);
                }
            }
        }
    }

    bool HasBaseType(Type type, string baseTypeName)
    {
        if (type == null) return false;

        string typeName = type.Name;

        if (baseTypeName == typeName) return true;

        return HasBaseType(type.GetTypeInfo().BaseType, baseTypeName);
    }

    bool ImplementsDictionary(Type t)
    {
        return t is IDictionary;
    }
}
2

Sie können Ihre eigene WriteLine-Methode schreiben.

public static void WriteLine<T>(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());
    }

Verwenden Sie es wie-

WriteLine(myObject);

Um eine Sammlung zu schreiben, können wir

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

Die Methode könnte so aussehen:

 public static void WriteLine<T>(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());
        }
    }

Mit if, else if und Überprüfen von Schnittstellen, Attributen, Basistyp usw. und Rekursion (da dies eine rekursive Methode ist) auf diese Weise können wir einen Objekt-Dumper erzielen, aber es ist mit Sicherheit mühsam. Wenn Sie den Objekt-Dumper aus dem LINQ-Beispiel von Microsoft verwenden, sparen Sie Zeit.

2
Ariful Islam