Каков наилучший способ выгрузки целых объектов в журнал в C #?

Поэтому для просмотра текущего состояния объекта во время выполнения мне действительно нравится то, что дает мне окно Visual Studio Immediate. Просто делаю простой

? objectname

Даст мне красиво отформатированный «дамп» объекта.

Есть ли простой способ сделать это в коде, чтобы я мог сделать что-то подобное при регистрации?

11.12.2008 17:58:32
В конце концов, я совсем немного использовал T.Dump. Это довольно солидное решение - нужно просто быть осторожным с рекурсией.
Dan Esparza 1.12.2015 13:23:01
Это старый вопрос, но он стоит на вершине множества поисковых запросов. Для будущих читателей: см. Это против расширения . Отлично работал для меня в VS2015.
Jesse Good 6.12.2015 01:20:32
Обновление для 2020 года, так как этот плагин VS не поддерживается и не имеет некоторых функций. Следующая библиотека делает то же самое в коде - и у нее есть несколько дополнительных функций, например, она отслеживает, где она уже посещена, чтобы избежать циклов: github.com/thomasgalliker/ObjectDumper
Nick Westgate 17.03.2020 04:17:33
13 ОТВЕТОВ
РЕШЕНИЕ

Вы можете основывать что-то на коде ObjectDumper, который поставляется с примерами Linq .
Также посмотрите на ответ на этот связанный вопрос, чтобы получить образец.

55
23.05.2017 12:26:10
Он также не работает для массивов (он просто отображает тип и длину массива, но не печатает его содержимое).
Konrad Morawski 20.09.2012 06:57:42
Пакет nuget для ObjectDumper теперь доступен. Он также предоставляет метод расширения DumpToStringи Dumpдля Objectкласса. Handy.
IsmailS 17.06.2015 09:43:53
w3wp.exeпадает, когда я пытаюсь использовать ObjectDumperподобноеRequest.DumpToString("aaa");
Paul 2.05.2016 15:39:00

Вы можете использовать отражение и пройтись по всем свойствам объекта, затем получить их значения и сохранить их в журнале. Форматирование действительно тривиально (вы можете использовать \ t для отступа свойств объекта и его значений):

MyObject
    Property1 = value
    Property2 = value2
    OtherObject
       OtherProperty = value ...
4
11.12.2008 18:05:35

Я уверен, что есть лучшие способы сделать это, но в прошлом я использовал метод, подобный следующему, чтобы сериализовать объект в строку, которую я могу записать:

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

Вы увидите, что метод может также возвращать исключение, а не сериализованный объект, поэтому вам нужно убедиться, что объекты, которые вы хотите регистрировать, являются сериализуемыми.

26
11.12.2008 18:08:54
В свете возможностей, добавленных в C # после того, как вы ответили, вопрос может быть полезным, чтобы указать, что эта реализация прекрасно работает как метод расширения. Если к объекту применяется класс Object и вы ссылаетесь на расширение везде, где вам это нужно, это может быть удобным способом вызова функции.
Nikita G. 10.11.2013 09:14:42
Я продолжаю получать от этого Failed to access type 'System.__ComObject' failed. Noob для C #, был бы признателен за помощь.
GuySoft 18.10.2014 18:50:21
@GuySoft Я подозреваю, что одно из свойств вашего объекта или самого объекта не сериализуемо.
Bernhard Hofmann 20.10.2014 09:15:45
К сожалению, этот метод нельзя использовать в классах без конструктора без параметров. Они не сериализуемы.
Jarekczek 2.09.2016 13:14:20

Что мне нравится делать, так это переопределять ToString (), так что я получаю более полезный вывод, кроме имени типа. Это удобно в отладчике, вы можете видеть информацию, которую вы хотите об объекте, без необходимости его расширения.

4
11.12.2008 19:05:22

ServiceStack.Text имеет метод расширения 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
    }
}
16
13.04.2020 19:03:42
Это не работает для полей. ОП явно спрашивал о «целых объектах».
Konrad Morawski 20.09.2012 07:04:24
He didn't say fields- сказал он entire objects, в который входят поля. Он также упомянул функцию Immediate Window в Visual Studio в качестве примера того, чего он хотел достичь ( «Простое выполнение ? objectnameдаст мне хорошо отформатированный« дамп »объекта» ). ? objectnameраспечатывает все поля также. This has been immensely helpful - one of my most used extension methods to date- Я не подвергаю сомнению, что это полезно, только что он сбрасывает целые объекты.
Konrad Morawski 20.09.2012 08:24:57
@KonradMorawski Неправильные целые объекты означают рекурсивный дамп объекта, а НЕ то, что он включает в себя поля, которые могут легко привести к бесконечному рекурсивному циклу. Вы не должны предполагать, что намекают другие. Мой ответ актуален и полезен, ваш отрицательный голос + комментарий - нет.
mythz 20.09.2012 09:08:54
@mythz да, конечно, вам нужно предотвратить переполнение стека (например, у каждого Int32поля есть MaxValueполе, которое Int32само по себе ...), это хорошая точка зрения, но это не меняет того факта, что объекты - и, конечно, целые - состоят из полей тоже, а не только из свойств. Более того (вы не адрес, один), ? objectnameв Immediate Window делает полей отображения - не вызывая бесконечный цикл. Если это из-за моего отрицательного голоса, я могу отозвать его (если вы позволите мне разблокировать его, то есть). Я в принципе не согласен.
Konrad Morawski 20.09.2012 09:33:15
-1 для ответа по существу только на ссылку, хотя выглядит здорово, если бы я мог его использовать! Возможно, я слепой, но я не могу найти источник по этой ссылке; две папки для загрузки пусты. Код слишком длинный, чтобы включить его в ответ?
user565869 14.07.2014 19:26:13

Вот тупо простой способ написать плоский объект, красиво отформатированный:

using Newtonsoft.Json.Linq;

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

Что происходит, так это то, что объект сначала преобразуется во внутреннее представление JSON JObject.FromObject, а затем преобразуется в строку JSON ToString. (И, конечно, строка JSON является очень хорошим представлением простого объекта, тем более, что он ToStringбудет содержать символы новой строки и отступы.) «ToString», конечно, является посторонним (как это подразумевается при использовании +для объединения строки и объекта), но Я хотел бы указать это здесь.

14
10.06.2014 21:08:11
JsonConvert.SerializeObject (спасибо, Formatting.Indented) для удобного чтения в журнале
Tertium 23.08.2016 23:04:45
HotLicks - я хочу сообщить вам, насколько важен этот вклад для меня сейчас. У меня есть требование провести аудит того, что изменилось во время обновления, и вы только что перенесли мой стресс с уровня «паники» обратно на управляемый уровень «беспокойства». Спасибо, сэр, пусть у вас будет очень долгая и благословенная жизнь
Iofacture 16.05.2019 22:25:43

Для более крупного графа объектов я использую 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.

Снимок экрана: окно Visual Studio 2013 Locals

Я использую Visual Studio 2013.

56
27.10.2014 21:32:02
SerializeObj -> SerializeObject?
Wiseman 27.10.2014 12:07:52
Блестяще, спасибо. Я не могу установить средства отладки для Visual Studio на моем удаленном сервере, и это прекрасно работает в моем приложении asp.net mvc.
Liam Kernighan 23.04.2018 17:45:30
Для хорошего форматирования вы можете сделать:Newtonsoft.Json.JsonConvert.SerializeObject(sampleData, Formatting.Indented)
Zorgarath 9.03.2019 05:55:33
гораздо проще, чем пытаться сделать это вручную. Это становится сложным
ahong 17.10.2019 08:54:21

Вы можете использовать Visual Studio Immediate Window

Просто вставьте это ( actualочевидно, измените имя вашего объекта):

Newtonsoft.Json.JsonConvert.SerializeObject(actual);

Должен печатать объект в формате JSON введите описание изображения здесь

Вы должны иметь возможность скопировать его поверх текстового механического текстового инструмента или блокнота ++ и заменить экранированные кавычки ( \") на "и newlines ( \r\n) пустым пространством, затем удалить двойные кавычки ( ") из начала и конца и вставить его в jsbeautifier, чтобы сделать его более читабельным.

ОБНОВЛЕНИЕ комментария ОП

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

это должно позволить вам сбросить любой объект.

Надеюсь, это сэкономит вам время.

21
23.06.2015 16:05:03
Спасибо. Возможно, вы не уловили его в моем первоначальном вопросе, но я указал, что я уже знал о ближайшем окне, и я хотел сделать то же самое при входе в мое приложение.
Dan Esparza 23.06.2015 15:38:55
@DanEsparza Console.Log(Newtonsoft.Json.JsonConvert.SerializeObject(actual));? :) и да, я действительно пропустил это. Этот вопрос возникает при поиске google.co.uk/...
Matas Vaitkevicius 23.06.2015 15:52:29
К вашему сведению, если у вас есть строка JSON в строке C #, щелкните значок Spyglass справа от строки и выберите текстовый визуализатор. Откроется окно, в котором отображается текстовая версия строки JSON (без кавычек или \ r \ n).
Walter 31.08.2016 01:00:37

Я нашел библиотеку под названием ObjectPrinter, которая позволяет легко выгружать объекты и коллекции в строки (и многое другое). Это именно то, что мне было нужно.

3
25.08.2015 12:06:50

Вы можете написать свой собственный метод 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и проверяя интерфейсы, атрибуты, базовый тип и т. Д. И рекурсию (так как это рекурсивный метод), мы можем получить объектный дампер, но это наверняка утомительно. Использование дампера объектов из примера LINQ от Microsoft сэкономит ваше время.

2
2.03.2016 06:28:37
Из любопытства: как это обрабатывает массивы или списки? Или свойства, которые ссылаются на родительские объекты?
Dan Esparza 1.03.2016 14:50:03
@DanEsparza Спасибо, чтобы показать мне способ быть более конкретным.
Ariful Islam 2.03.2016 06:33:17

Ниже приведена еще одна версия, которая делает то же самое (и обрабатывает вложенные свойства), которая, на мой взгляд, более проста (не зависит от внешних библиотек и может быть легко изменена для выполнения других операций, кроме ведения журнала):

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
21.02.2017 02:40:49
это ужасно умрет, если у вас будет Dateсвойство в вашем внутреннем объекте ... просто сказать ...
Noctis 7.09.2017 04:43:05

Основываясь на ответе @engineforce, я создал этот класс, который использую в проекте PCL решения 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;
    }
}
2
11.11.2018 22:09:24

Все приведенные выше пути предполагают, что ваши объекты сериализуются в XML или JSON,
или вы должны реализовать собственное решение.

Но, в конце концов, вы дошли до того, что вам придется решать такие проблемы, как

  • рекурсия в объектах
  • несериализуемые объекты
  • исключения
  • ...

Плюс журнал, который вы хотите больше информации:

  • когда произошло событие
  • стек вызовов
  • какая тройка
  • что было в веб-сессии
  • какой IP-адрес
  • URL
  • ...

Существует лучшее решение, которое решает все это и многое другое.
Используйте этот пакет Nuget : Desharp .
Для всех типов приложений - как веб-, так и настольных приложений .
Смотрите документацию Desharp Github . У этого есть много вариантов конфигурации .

Просто позвоните куда угодно:

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
  • он может сохранить журнал в хорошем HTML (или в формате TEXT, настраивается)
  • возможно написать дополнительно в фоновом потоке (настраивается)
  • есть опции для максимальной глубины объектов и максимальной длины строк (настраивается)
  • он использует циклы для повторяющихся объектов и обратное отражение для всего остального, в
    действительности для всего, что вы можете найти в среде .NET .

Я верю, что это поможет.

0
27.09.2019 09:11:35