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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/360277/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 00:30:40  来源:igfitidea点击:

What is the best way to dump entire objects to a log in C#?

c#visual-studiodebuggingobjectlogging

提问by Dan Esparza

So for viewing a current object's state at runtime, I really like what the Visual Studio Immediate window gives me. Just doing a simple

所以为了在运行时查看当前对象的状态,我真的很喜欢 Visual Studio 立即窗口给我的东西。做一个简单的

? objectname

Will give me a nicely formatted 'dump' of the object.

会给我一个格式很好的对象“转储”。

Is there an easy way to do this in code, so I can do something similar when logging?

有没有一种简单的方法可以在代码中做到这一点,所以我可以在记录时做类似的事情?

采纳答案by Mike Scott

You could base something on the ObjectDumper code that ships with the Linq samples.
Have also a look at the answer of this related questionto get a sample.

您可以基于随Linq 示例一起提供的 ObjectDumper 代码。
另请查看此相关问题的答案以获取示例。

回答by Ricardo Villamil

You could use reflection and loop through all the object properties, then get their values and save them to the log. The formatting is really trivial (you could use \t to indent an objects properties and its values):

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

MyObject
    Property1 = value
    Property2 = value2
    OtherObject
       OtherProperty = value ...

回答by Bernhard Hofmann

I'm certain there are better ways of doing this, but I have in the past used a method something like the following to serialize an object into a string that I can log:

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

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

You'll see that the method might also return the exception rather than the serialized object, so you'll want to ensure that the objects you want to log are serializable.

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

回答by Darryl Braaten

What I like doing is overriding ToString() so that I get more useful output beyond the type name. This is handy in the debugger, you can see the information you want about an object without needing to expand it.

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

回答by mythz

ServiceStack.Texthas a T.Dump() extension methodthat does exactly this, recursively dumps all properties of any type in a nice readable format.

ServiceStack.Text有一个T.Dump() 扩展方法可以做到这一点,以一种很好的可读格式递归转储任何类型的所有属性。

Example usage:

用法示例:

var model = new TestModel();
Console.WriteLine(model.Dump());

and output:

和输出:

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

回答by Hot Licks

Here is a stupidly simple way to write a flat object, nicely formatted:

这是编写平面对象的一种非常简单的方法,格式很好:

using Newtonsoft.Json.Linq;

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

What's going on is that the object is first converted to a JSON internal representation by JObject.FromObject, and then converted to JSON string by ToString. (And of course a JSON string is a very nice representation of a simple object, especially since ToStringwill include newlines and indents.) The "ToString" is of course extraneous (as it's implied by using +to concat a string and an object), but I kinda like to specify it here.

发生的事情是先将对象由 转换为 JSON 内部表示JObject.FromObject,然后由转换为 JSON 字符串ToString。(当然,JSON 字符串是简单对象的一种非常好的表示,尤其是因为ToString将包含换行符和缩进。)“ToString”当然是无关紧要的(因为它通过使用+连接字符串和对象来暗示),但是我有点想在这里指定它。

回答by Jason

For a larger object graph, I second the use of Json but with a slightly different strategy. First I have a static class that is easy to call and with a static method that wraps the Json conversion (note: could make this an extension method).

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

using Newtonsoft.Json;

public static class F
{
    public static string Dump(object obj)
    {
        return JsonConvert.SerializeObject(obj);
    }
}

Then in your Immediate Window,

然后在你的Immediate Window,

var lookHere = F.Dump(myobj);

lookHere will auto-show up in the Localswindow prepended with a $ or you can add a watch to it. On the right hand side of the Valuecolumn in the inspector, there is a magnifying glass with a dropdown caret beside it. Choose the dropdown caret and choose Json visualizer.

lookHere 将自动显示在Locals前面带有 $的窗口中,或者您可以向其中添加手表。在Value检查器列的右侧,有一个放大镜,旁边有一个下拉插入符号。选择下拉插入符号并选择 Json 可视化工具。

Screenshot of Visual Studio 2013 Locals window

Visual Studio 2013 Locals 窗口的屏幕截图

I am using Visual Studio 2013.

我正在使用 Visual Studio 2013。

回答by Matas Vaitkevicius

You could use Visual Studio Immediate Window

您可以使用 Visual Studio 立即窗口

Just paste this (change actualto your object name obviously):

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

Newtonsoft.Json.JsonConvert.SerializeObject(actual);

It should print object in JSON enter image description here

它应该在 JSON 中打印对象 在此处输入图片说明

You should be able to copy it over textmechanic text toolor notepad++and replace escaped quotes (\") with "and newlines (\r\n) with empty space, then remove double quotes (") from beginning and end and paste it to jsbeautifierto make it more readable.

您应该能够将其复制到 textmechanic 文本工具记事本 ++ 上,并用空格替换转义引号 ( \")"并将换行符 ( \r\n) 替换为空格,然后"从开头和结尾删除双引号 ( ) 并将其粘贴到jsbeautifier以使其更具可读性。

UPDATE to OP's comment

更新 OP 的评论

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

this should allow you to dump any object.

这应该允许您转储任何对象。

Hope this saves you some time.

希望这可以为您节省一些时间。

回答by Marek Dzikiewicz

I found a library called ObjectPrinterwhich allows to easily dump objects and collections to strings (and more). It does exactly what I needed.

我找到了一个名为ObjectPrinter的库,它允许轻松地将对象和集合转储到字符串(等等)。它正是我所需要的。

回答by Ariful Islam

You can write your own WriteLine method-

您可以编写自己的 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());
    }

Use it like-

使用它就像 -

WriteLine(myObject);

To write a collection we can use-

要编写一个集合,我们可以使用-

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

The method may look like-

该方法可能看起来像-

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

Using if, else ifand checking interfaces, attributes, base type, etc. and recursion (as this is a recursive method) in this way we may achieve an object dumper, but it is tedious for sure. Using the object dumper from Microsoft's LINQ Sample would save your time.

if, else if以这种方式使用和检查接口、属性、基类型等和递归(因为这是一种递归方法)我们可以实现一个对象转储器,但它肯定是乏味的。使用 Microsoft 的 LINQ 示例中的对象转储程序可以节省您的时间。