Więc jeśli chodzi o przeglądanie stanu bieżącego obiektu w czasie wykonywania, bardzo podoba mi się to, co daje mi okno Visual Studio Immediate. Po prostu robię proste
? objectname
Da mi ładnie sformatowany „zrzut” obiektu.
Czy istnieje łatwy sposób na zrobienie tego w kodzie, abym mógł zrobić coś podobnego podczas logowania?
Odpowiedzi:
Możesz oprzeć coś na kodzie ObjectDumper, który jest dostarczany z próbkami Linq .
Spójrz również na odpowiedź na to powiązane pytanie, aby pobrać próbkę.
źródło
DumpToString
iDump
doObject
klasy. Poręczny.w3wp.exe
ulega awarii, gdy próbuję użyćObjectDumper
Request.DumpToString("aaa");
W przypadku większego grafu obiektowego popieram użycie Json, ale z nieco inną strategią. Najpierw mam statyczną klasę, która jest łatwa do wywołania i ze statyczną metodą, która otacza konwersję Json (uwaga: może to uczynić metodę rozszerzającą).
using Newtonsoft.Json; public static class F { public static string Dump(object obj) { return JsonConvert.SerializeObject(obj); } }
Następnie w twoim
Immediate Window
,var lookHere = F.Dump(myobj);
look Tutaj pojawi się automatycznie w
Locals
oknie poprzedzonym znakiem $ lub możesz dodać do niego zegarek. Po prawej stronieValue
kolumny w inspektorze znajduje się szkło powiększające z rozwijaną kropką obok. Wybierz rozwijany kursor i wybierz wizualizator Json.Używam Visual Studio 2013.
źródło
Newtonsoft.Json.JsonConvert.SerializeObject(sampleData, Formatting.Indented)
System.Text.Json.JsonSerializer.Serialize(yourObject)
.Jestem pewien, że istnieją lepsze sposoby na zrobienie tego, ale w przeszłości korzystałem z metody podobnej do poniższej, aby serializować obiekt w ciąg, który mogę rejestrować:
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; }
Zobaczysz, że metoda może również zwrócić wyjątek zamiast zserializowanego obiektu, więc będziesz chciał upewnić się, że obiekty, które chcesz rejestrować, są serializowane.
źródło
Failed to access type 'System.__ComObject' failed
. Noob do c #, byłby wdzięczny za pomoc.Możesz użyć programu Visual Studio Immediate Window
Po prostu wklej to (
actual
oczywiście zmień na nazwę obiektu):Powinien wydrukować obiekt w formacie JSON
Powinieneś być w stanie skopiować go za pomocą narzędzia tekstowego mechanicznego lub notatnika ++ i zamienić cudzysłowy (
\"
) na"
i newlines (\r\n
) na puste miejsce, a następnie usunąć podwójne cudzysłowy ("
) z początku i końca i wkleić go do jsbeautifier, aby był bardziej czytelny.UPDATE do komentarza OP
public static class Dumper { public static void Dump(this object obj) { Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(obj)); // your logger } }
powinno to pozwolić na zrzucenie dowolnego obiektu.
Mam nadzieję, że zaoszczędzi ci to trochę czasu.
źródło
Console.Log(Newtonsoft.Json.JsonConvert.SerializeObject(actual));
? :) i tak, rzeczywiście tęskniłem. To pytanie pojawia się podczas wyszukiwania google.co.uk/…ServiceStack.Text ma metodę rozszerzenia T.Dump (), która robi dokładnie to, rekurencyjnie zrzuca wszystkie właściwości dowolnego typu w ładnym, czytelnym formacie.
Przykładowe użycie:
var model = new TestModel(); Console.WriteLine(model.Dump());
i wyjście:
{ 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 } }
źródło
He didn't say fields
- powiedziałentire objects
, co obejmuje pola. Wspomniał również o funkcji Immediate Window w Visual Studio jako przykład tego, co chciał osiągnąć ( „Wykonanie prostego polecenia? objectname
da mi ładnie sformatowany zrzut obiektu” ).? objectname
wypisuje również wszystkie pola.This has been immensely helpful - one of my most used extension methods to date
- Nie kwestionuję, że jest przydatny, tylko że zrzuca całe obiekty.Int32
pole maMaxValue
pole, które jestInt32
samo w sobie ...), to dobra uwaga, ale nie zmienia to faktu, że obiekty - a na pewno całe - składają się również z pól, a nie tylko z właściwości. Co więcej (nie odniósł się, że jeden),? objectname
wImmediate Window
robi pól wyświetlacza - bez wyzwalania nieskończoną pętlę. Jeśli chodzi o mój głos przeciw, mogę go wycofać (to znaczy, jeśli pozwolisz mi go odblokować). W zasadzie i tak się z tym nie zgadzam.Oto głupio prosty sposób na napisanie płaskiego obiektu, ładnie sformatowanego:
using Newtonsoft.Json.Linq; Debug.WriteLine("The object is " + JObject.FromObject(theObjectToDump).ToString());
Chodzi o to, że obiekt jest najpierw konwertowany na wewnętrzną reprezentację JSON przez
JObject.FromObject
, a następnie konwertowany na ciąg JSON przezToString
. (I oczywiście ciąg JSON jest bardzo ładną reprezentacją prostego obiektu, zwłaszcza żeToString
będzie zawierał znaki nowej linii i wcięcia.) „ToString” jest oczywiście nieistotne (jak to wynika z użycia+
do łączenia ciągu i obiektu), ale Lubię to tutaj określać.źródło
Możesz użyć odbicia i zapętlić wszystkie właściwości obiektu, a następnie pobrać ich wartości i zapisać je w dzienniku. Formatowanie jest naprawdę trywialne (możesz użyć \ t do wcięcia właściwości obiektu i jego wartości):
MyObject Property1 = value Property2 = value2 OtherObject OtherProperty = value ...
źródło
Lubię zastępować ToString (), aby uzyskać bardziej przydatne dane wyjściowe poza nazwą typu. Jest to przydatne w debugerze, możesz zobaczyć potrzebne informacje o obiekcie bez konieczności jego rozwijania.
źródło
Znalazłem bibliotekę o nazwie ObjectPrinter, która pozwala na łatwe zrzucanie obiektów i kolekcji do łańcuchów (i nie tylko). Robi dokładnie to, czego potrzebowałem.
źródło
Poniżej znajduje się kolejna wersja, która robi to samo (i obsługuje zagnieżdżone właściwości), co moim zdaniem jest prostsze (brak zależności od bibliotek zewnętrznych i można je łatwo zmodyfikować, aby robić inne rzeczy niż rejestrowanie):
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")); } }
źródło
Date
własność w swoim wewnętrznym obiekcie ... po prostu mówiąc ...Możesz napisać własną metodę WriteLine-
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()); }
Użyj tego jak-
Aby napisać kolekcję, możemy użyć-
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); } }
Metoda może wyglądać następująco:
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()); } }
Używając
if, else if
i sprawdzając interfejsy, atrybuty, typ bazowy itp. Oraz rekurencję (ponieważ jest to metoda rekurencyjna) w ten sposób możemy uzyskać zrzut obiektu, ale na pewno jest to uciążliwe. Korzystanie z obiektu zrzutu z LINQ Sample firmy Microsoft pozwoliłoby zaoszczędzić czas.źródło
Na podstawie odpowiedzi @engineforce utworzyłem tę klasę, której używam w projekcie PCL rozwiązania Xamarin:
/// <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; } }
źródło
We wszystkich powyższych ścieżkach założono, że obiekty można serializować do formatu XML lub JSON
albo trzeba zaimplementować własne rozwiązanie.
Ale w końcu nadal dochodzisz do punktu, w którym musisz rozwiązać problemy, takie jak
Plus log, aby uzyskać więcej informacji:
Jest najlepsze rozwiązanie, które rozwiązuje to wszystko i wiele więcej.
Użyj tego pakietu Nuget : Desharp .
Do wszystkich typów aplikacji - zarówno internetowych, jak i stacjonarnych .
Zobacz dokumentację Desharp Github . Posiada wiele opcji konfiguracyjnych .
Po prostu zadzwoń wszędzie:
Desharp.Debug.Log(anyException); Desharp.Debug.Log(anyCustomValueObject); Desharp.Debug.Log(anyNonserializableObject); Desharp.Debug.Log(anyFunc); Desharp.Debug.Log(anyFunc, Desharp.Level.EMERGENCY); // you can store into different files
właściwie dla wszystkiego, co można znaleźć w środowisku .NET .
Wierzę, że to pomoże.
źródło