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



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



? objectname


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



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

590   11  

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.

Screenshot of Visual Studio 2013 Locals window

я использую 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 enter image description here

вы должны быть в состоянии скопировать его за 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

    Ничего не найдено.