将整个对象转储到C#中的日志的最佳方法是什么?

Dan*_*rza 118 c# debugging logging object visual-studio

因此,为了在运行时查看当前对象的状态,我非常喜欢Visual Studio立即窗口给出的内容.只是做一个简单的

? objectname
Run Code Online (Sandbox Code Playgroud)

将给我一个格式良好的"转储"对象.

有没有一种简单的方法在代码中执行此操作,因此我可以在记录时执行类似的操作?

Mik*_*ott 55

您可以基于Linq示例附带的ObjectDumper代码.
还要看一下这个相关问题的答案,以获得样本.

  • 它也不适用于数组(它只显示数组的类型和长度,但不打印其内容). (4认同)
  • [ObjectDumper的nuget包](http://www.nuget.org/packages/ObjectDumper/)现已推出.它还提供了一个扩展方法`DumpToString`和`Dump`到`Object`类.便利. (4认同)
  • `w3wp.exe` 在我尝试使用 `ObjectDumper` 时崩溃,比如 `Request.DumpToString("aaa");` (2认同)

Jas*_*son 52

对于更大的对象图,我第二次使用Json,但策略略有不同.首先,我有一个易于调用的静态类,并使用一个包装Json转换的静态方法(注意:可以使它成为一个扩展方法).

using Newtonsoft.Json;

public static class F
{
    public static string Dump(object obj)
    {
        return JsonConvert.SerializeObject(obj);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的Immediate Window,

var lookHere = F.Dump(myobj);
Run Code Online (Sandbox Code Playgroud)

lookHere会自动显示在Locals$前面的窗口中,或者你可以添加一个手表.在Value检查员栏目的右侧,有一个放大镜,旁边有一个下拉插入物.选择下拉插入符并选择Json visualizer.

Visual Studio 2013 Locals窗口的屏幕截图

我正在使用Visual Studio 2013.

  • 在 .NET Core 3.1 和 .NET 5+ 中,您还可以使用开箱即用的 API `System.Text.Json.JsonSerializer.Serialize(yourObject)`。 (6认同)
  • SerializeObj - > SerializeObject? (2认同)
  • 对于漂亮的格式,你可以这样做:`Newtonsoft.Json.JsonConvert.SerializeObject(sampleData, Formatting.Indented)` (2认同)

Ber*_*ann 26

我确定有更好的方法可以做到这一点,但我过去使用类似下面的方法将对象序列化为一个我可以记录的字符串:

  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;
  }
Run Code Online (Sandbox Code Playgroud)

您将看到该方法也可能返回异常而不是序列化对象,因此您需要确保要记录的对象是可序列化的.

  • 根据在回答问题后添加到C#的功能可能有助于指出此实现作为扩展方法很好地工作.如果应用于Object类并且您在需要的任何地方引用扩展,那么它可以是调用该函数的便捷方式. (2认同)

Mat*_*ius 20

您可以使用Visual Studio立即窗口

只需粘贴(actual显然更改为您的对象名称):

Newtonsoft.Json.JsonConvert.SerializeObject(actual);
Run Code Online (Sandbox Code Playgroud)

它应该用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
    }
}
Run Code Online (Sandbox Code Playgroud)

这应该允许你转储任何对象.

希望这能为您节省一些时间.

  • 仅供参考,当您在C#字符串中包含JSON字符串时,请单击字符串右侧的望远镜图标,然后选择“文本可视化工具”。它将打开一个窗口,该窗口显示JSON字符串的纯文本版本(非转义引号或\ r \ n)。 (2认同)

myt*_*thz 17

我有一个完全正确的T.Dump()扩展方法,递归地以一种可读的格式转储任何类型的所有属性.

用法示例:

var model = new TestModel();
Console.WriteLine(model.Dump());
Run Code Online (Sandbox Code Playgroud)

并输出:

{
    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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • "他没有说田野" - 他说"整个物体",包括田野.他还提到Visual Studio的立即窗口功能作为他想要实现的一个例子(*"只做一个简单的`?objectname`将给我一个格式良好的'转储'对象"*).`?objectname`也打印出所有字段.`这非常有用 - 迄今为止我最常用的扩展方法之一 - 我不是在质疑它是否有用,只是它会转储整个对象. (5认同)
  • @KonradMorawski错误**整个对象**表示对象的递归转储,而不是它包含字段,这很容易导致无限递归循环.你不应该假设别人暗示的东西.我的回答既相关又有帮助,你的投票+评论不是. (3认同)
  • -1基本上只是一个链接答案,但如果我可以使用它看起来很棒!也许我是瞎子,但是我无法通过那个链接找到来源; 两个上传文件夹都是空的.代码是否太长而无法包含在答案中? (3认同)

Hot*_*cks 14

这是一个编写扁平对象的简单方法,格式很好:

using Newtonsoft.Json.Linq;

Debug.WriteLine("The object is " + JObject.FromObject(theObjectToDump).ToString());
Run Code Online (Sandbox Code Playgroud)

发生的事情是该对象首先被转换为JSON内部表示JObject.FromObject,然后转换为JSON字符串ToString.(当然,JSON字符串是一个非常好的简单对象表示,特别是因为ToString它将包含换行符和缩进.)"ToString"当然是无关紧要的(因为它是+用于连接字符串和对象所暗示的),但是我有点想在这里说明一下.

  • JsonConvert.SerializeObject(欣赏,Formatting.Indented),以便在日志中轻松阅读 (5认同)
  • HotLicks - 我想向您传达这一贡献现在对我来说有多么重要。我需要对更新期间发生的变化进行审核,而您刚刚将我的压力从“恐慌”级别降低到了可管理的“担忧”级别。谢谢您,先生,祝您长寿幸福 (5认同)

Ric*_*mil 5

您可以使用反射并循环遍历所有对象属性,然后获取它们的值并将它们保存到日志中。格式设置确实很简单(您可以使用 \t 来缩进对象属性及其值):

MyObject
    Property1 = value
    Property2 = value2
    OtherObject
       OtherProperty = value ...
Run Code Online (Sandbox Code Playgroud)


Dar*_*ten 5

我喜欢做的是重写 ToString() ,以便获得类型名称之外的更有用的输出。这在调试器中很方便,您可以查看所需的有关对象的信息,而无需展开它。


eng*_*rce 5

以下是执行相同操作(并处理嵌套属性)的另一个版本,我认为它更简单(不依赖于外部库,并且可以轻松修改以执行日志记录以外的操作):

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"));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你的内部对象中有一个“Date”属性,这将会可怕地消失......只是说...... (2认同)

Len*_*rri 5

今天,您甚至不需要外部依赖。您可以只使用内置的Microsoft Json Serializer

using System;
using System.Text.Json;

namespace MyCompany.Core.Extensions
{
    public static class ObjectExtensions
    {
        public static string Dump(this object obj)
        {
            try
            {
                return JsonSerializer.Serialize(obj);
            }
            catch(Exception)
            {
                return string.Empty;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您可以传递JsonSerializerOptions参数来根据您的喜好进一步自定义序列化:

在此输入图像描述

假设您想编写缩进的 JSON 以便于阅读...我们将使用:

   new JsonSerializerOptions { WriteIndented = true }
Run Code Online (Sandbox Code Playgroud)

#######

如果您希望从 迁移NewtonSoft.Json到 ,这里有一个很好的指南System.Text.Json

将 Newtonsoft.Json 与 System.Text.Json 进行比较,并迁移到 System.Text.Json