Каков наилучший способ сброса всех объектов в журнал на C#?
поэтому для просмотра состояния текущего объекта во время выполнения мне очень нравится то, что дает мне окно Visual Studio Immediate. Просто делаю простой
? objectname
даст мне красиво отформатированный "дамп" объекта.
есть ли простой способ сделать это в коде, так что я могу сделать что-то подобное при регистрации?
11 ответов:
вы можете основывать что-то на коде ObjectDumper, который поставляется с примеры LINQ.
Также посмотрите на ответ этого вопрос чтобы получить образец.
для более крупного графа объектов я поддерживаю использование Json, но с немного другой стратегией. Сначала у меня есть статический класс, который легко вызвать и со статическим методом, который обертывает преобразование Json (Примечание: может сделать это методом расширения).
using Newtonsoft.Json; public static class F { public static string Dump(object obj) { return JsonConvert.SerializeObject(obj); } }затем в
Immediate Window,var lookHere = F.Dump(myobj);lookHere будет автоматически отображаться в
Localsокно с добавлением $ или вы можете добавить часы к нему. На правой сторонеValueколонка в инспекторе, там это увеличительное стекло с выпадающим кареткой рядом с ним. Выберите раскрывающийся список и выберите JSON visualizer.
я использую Visual Studio 2013.
Я уверен, что есть лучшие способы сделать это, но я в прошлом использовал метод что-то вроде следующего, чтобы сериализовать объект в строку, которую я могу записать:
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; }вы увидите, что метод также может возвращать исключение, а не сериализованный объект, поэтому вы хотите убедиться, что объекты, которые вы хотите зарегистрировать, сериализуемы.
у меня есть T. Dump () метод расширения это делает именно это, рекурсивно сбрасывает все свойства любого типа в удобном для чтения формате.
пример использования:
var model = new TestModel(); Console.WriteLine(model.Dump());и выход:
{ 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 } }
вы можете использовать Visual Studio немедленное окно
просто вставьте это (изменить
actualк вашему имени объекта очевидно):Newtonsoft.Json.JsonConvert.SerializeObject(actual);он должен печатать объект в JSON
вы должны быть в состоянии скопировать его за textmechanic инструмент "Текст" или Блокнот++ и заменить экранированные кавычки (
\") С"и строк (\r\n) С пустым пространством, затем удалите двойные кавычки (") от начала и конца и вставить его к jsbeautifier чтобы сделать его более читабельным.обновить комментарий OP
public static class Dumper { public static void Dump(this object obj) { Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(obj)); // your logger } }это должно позволить вам сбросить любой объект.
надеюсь, что это экономит ваше время.
вот глупо простой способ написать плоский объект, красиво отформатированный:
using Newtonsoft.Json.Linq; Debug.WriteLine("The object is " + JObject.FromObject(theObjectToDump).ToString());что происходит, так это то, что объект сначала преобразуется во внутреннее представление JSON с помощью
JObject.FromObject, а затем преобразуется в строку JSON с помощьюToString. (И, конечно же, строка JSON-это очень хорошее представление простого объекта, тем более чтоToStringбудет включать новые строки и отступы.) "ToString", конечно, посторонний (как это подразумевается с помощью+для объединения строки и объект), но я вроде как хотел бы указать его здесь.
вы могли бы использовать отражение и перебрать все свойства объекта, а затем получить их значения и сохранить их в журнале. Форматирование действительно тривиально (вы можете использовать \t для отступа свойств объектов и его значений):
MyObject Property1 = value Property2 = value2 OtherObject OtherProperty = value ...
то, что мне нравится делать, это переопределение ToString (), чтобы я получал более полезный вывод за пределами имени типа. Это удобно в отладчике, вы можете увидеть информацию, которую вы хотите о объекте без необходимости его расширения.
Я нашел библиотеку под названием ObjectPrinter что позволяет легко сбрасывать объекты и коллекции в строки (и более). Это именно то, что мне нужно.
вы можете написать свой собственный метод 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()); }использовать его как-
WriteLine(myObject);для написания коллекции мы можем использовать -
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); } }метод может выглядеть так-
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()); } }используя
if, else ifи проверка интерфейсов, атрибутов, базового типа и т. д. и рекурсия (так как это рекурсивный метод) таким образом мы можем достичь объекта dumper, но это утомительно наверняка. Использование дамп-объекта из примера LINQ от Microsoft позволит сохранить ваш время.
Ниже приведена другая версия, которая делает то же самое (и обрабатывает вложенные свойства), которая, я думаю, проще (нет зависимостей от внешних библиотек и может быть легко изменена для выполнения других задач, кроме ведения журнала):
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")); } }


Comments