55

我正在寻找一个可以以类似于以下格式输出对象及其所有叶值的类:

User
  - Name: Gordon
  - Age : 60
  - WorkAddress
     - Street: 10 Downing Street
     - Town: London
     - Country: UK
  - HomeAddresses[0]
    ...
  - HomeAddresses[1]
    ...

(或更清晰的格式)。这相当于:

public class User
{
    public string Name { get;set; }
    public int Age { get;set; }
    public Address WorkAddress { get;set; }
    public List<Address> HomeAddresses { get;set; }
}

public class Address
{
    public string Street { get;set; }
    public string Town { get;set; }
    public string Country { get;set; }
}

PropertyGrid 控件的一种字符串表示形式,无需为每种类型实现大量设计器。

PHP 有一个叫做var_dump的东西。我不想用手表,因为这是打印出来的。

如果它存在,谁能指出我这样的东西?或者,写一个赏金。

4

12 回答 12

55

sgmoore 链接中发布的对象转储程序:

//Copyright (C) Microsoft Corporation.  All rights reserved.

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

// See the ReadMe.html for additional information
public class ObjectDumper {

    public static void Write(object element)
    {
        Write(element, 0);
    }

    public static void Write(object element, int depth)
    {
        Write(element, depth, Console.Out);
    }

    public static void Write(object element, int depth, TextWriter log)
    {
        ObjectDumper dumper = new ObjectDumper(depth);
        dumper.writer = log;
        dumper.WriteObject(null, element);
    }

    TextWriter writer;
    int pos;
    int level;
    int depth;

    private ObjectDumper(int depth)
    {
        this.depth = depth;
    }

    private void Write(string s)
    {
        if (s != null) {
            writer.Write(s);
            pos += s.Length;
        }
    }

    private void WriteIndent()
    {
        for (int i = 0; i < level; i++) writer.Write("  ");
    }

    private void WriteLine()
    {
        writer.WriteLine();
        pos = 0;
    }

    private void WriteTab()
    {
        Write("  ");
        while (pos % 8 != 0) Write(" ");
    }

    private void WriteObject(string prefix, object element)
    {
        if (element == null || element is ValueType || element is string) {
            WriteIndent();
            Write(prefix);
            WriteValue(element);
            WriteLine();
        }
        else {
            IEnumerable enumerableElement = element as IEnumerable;
            if (enumerableElement != null) {
                foreach (object item in enumerableElement) {
                    if (item is IEnumerable && !(item is string)) {
                        WriteIndent();
                        Write(prefix);
                        Write("...");
                        WriteLine();
                        if (level < depth) {
                            level++;
                            WriteObject(prefix, item);
                            level--;
                        }
                    }
                    else {
                        WriteObject(prefix, item);
                    }
                }
            }
            else {
                MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
                WriteIndent();
                Write(prefix);
                bool propWritten = false;
                foreach (MemberInfo m in members) {
                    FieldInfo f = m as FieldInfo;
                    PropertyInfo p = m as PropertyInfo;
                    if (f != null || p != null) {
                        if (propWritten) {
                            WriteTab();
                        }
                        else {
                            propWritten = true;
                        }
                        Write(m.Name);
                        Write("=");
                        Type t = f != null ? f.FieldType : p.PropertyType;
                        if (t.IsValueType || t == typeof(string)) {
                            WriteValue(f != null ? f.GetValue(element) : p.GetValue(element, null));
                        }
                        else {
                            if (typeof(IEnumerable).IsAssignableFrom(t)) {
                                Write("...");
                            }
                            else {
                                Write("{ }");
                            }
                        }
                    }
                }
                if (propWritten) WriteLine();
                if (level < depth) {
                    foreach (MemberInfo m in members) {
                        FieldInfo f = m as FieldInfo;
                        PropertyInfo p = m as PropertyInfo;
                        if (f != null || p != null) {
                            Type t = f != null ? f.FieldType : p.PropertyType;
                            if (!(t.IsValueType || t == typeof(string))) {
                                object value = f != null ? f.GetValue(element) : p.GetValue(element, null);
                                if (value != null) {
                                    level++;
                                    WriteObject(m.Name + ": ", value);
                                    level--;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private void WriteValue(object o)
    {
        if (o == null) {
            Write("null");
        }
        else if (o is DateTime) {
            Write(((DateTime)o).ToShortDateString());
        }
        else if (o is ValueType || o is string) {
            Write(o.ToString());
        }
        else if (o is IEnumerable) {
            Write("...");
        }
        else {
            Write("{ }");
        }
    }
}

2015 更新

YAML 也很好地达到了这个目的,这就是使用 YamlDotNet 的方式

install-package YamlDotNet

    private static void DumpAsYaml(object o)
    {
        var stringBuilder = new StringBuilder();
        var serializer = new Serializer();
        serializer.Serialize(new IndentedTextWriter(new StringWriter(stringBuilder)), o);
        Console.WriteLine(stringBuilder);
    }
于 2009-08-28T15:10:36.163 回答
31

您可以使用 JSON 序列化程序,对于习惯使用 JSON 的任何人来说,它都应该易于阅读

User theUser = new User();
theUser.Name = "Joe";
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(myPerson.GetType());
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, theUser );
string json = Encoding.Default.GetString(ms.ToArray()); 
于 2009-08-28T15:21:15.097 回答
14

2019 年更新

您可以在 GitHub 上找到ObjectDumper 项目。您还可以通过 NuGet 包管理器通过 Visual Studio添加它。

于 2011-08-08T13:21:13.457 回答
12

如果您使用标记,System.Web.ObjectInfo.Print( ASP.NET Web Pages 2 ) 将完成此操作,并为 HTML 格式化。

例如:

@ObjectInfo.Print(new {
    Foo = "Hello",
    Bar = "World",
    Qux = new {
        Number = 42,
    },
})

在网页中,产生:

ObjectInfo.Print(...)

于 2013-01-22T20:31:42.697 回答
12

这是我为此编写的一个视觉工作室扩展:

https://visualstudiogallery.msdn.microsoft.com/c6a21c68-f815-4895-999f-cd0885d8774f

在行动: 对象导出器在行动

于 2015-04-26T00:49:25.997 回答
9

我知道这是一个老问题,但我想我会抛出一个对我有用的替代方案,花了我大约两分钟的时间。

安装 Newtonsoft Json.NET:http://james.newtonking.com/json

(或 nuget 版本)http://www.nuget.org/packages/newtonsoft.json/

参考组装:

using Newtonsoft.Json;

转储 JSON 字符串以记录:

txtResult.Text = JsonConvert.SerializeObject(testObj);
于 2013-11-26T19:05:23.973 回答
7

稍加思考就可以很容易地写出来。有点像:

public void Print(object value, int depth)
{
    foreach(var property in value.GetType().GetProperties())
    {
        var subValue = property.GetValue(value);
        if(subValue is IEnumerable)
        {
             PrintArray(property, (IEnumerable)subValue);
        }
        else
        {
             PrintProperty(property, subValue);
        }         
    }
}

您可以编写 PrintArray 和 PrintProperty 方法。

于 2009-08-28T14:33:06.817 回答
7

我有一个方便的 T.Dump() 扩展方法,它应该非常接近您正在寻找的结果。作为一种扩展方法,它是非侵入性的,应该适用于所有 POCO 对象。

示例用法

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
    }
}
于 2011-01-24T08:33:10.027 回答
2

如果您不想复制和粘贴 Chris S 的代码,Visual Studio 2008 示例附带一个 ObjectDumper。

驱动器:\Program Files\Microsoft Visual Studio 9.0\Samples\1033\LinqSamples\ObjectDumper

于 2009-08-28T15:20:47.267 回答
2

这是一个替代方案:

using System.Reflection;
public void Print(object value)
{
    PropertyInfo[] myPropertyInfo;
    string temp="Properties of "+value+" are:\n";
    myPropertyInfo = value.GetType().GetProperties();
    for (int i = 0; i < myPropertyInfo.Length; i++)
    {
        temp+=myPropertyInfo[i].ToString().PadRight(50)+" = "+myPropertyInfo[i].GetValue(value, null)+"\n";
    }
    MessageBox.Show(temp);
}

(只是触及1级,没有深度,但说了很多)

于 2011-11-08T11:41:32.843 回答
1

对于大多数类,您可以使用DataContractSerializer

于 2010-12-21T23:02:57.437 回答
1

我刚刚在 Blazor 项目中遇到了类似的要求,并提出了以下非常简单的组件来将对象(以及它的子对象)数据输出到屏幕:

ObjectDumper.razor:

@using Microsoft.AspNetCore.Components
@using Newtonsoft.Json

  <div>
    <button onclick="@DumpVMToConsole">@ButtonText</button>
    <pre id="json">@_objectAsJson</pre>
  </div>


@functions {

  // This component allows the easy visualisation of the values currently held in 
  // an object and its child objects.  Add this component to a page and pass in a 
  // param for the object to monitor, then press the button to see the object's data
  // as nicely formatted JSON
  // Use like this:  <ObjectDumper ObjectToDump="@_billOfLadingVM" />

  [Parameter]
  private object ObjectToDump { get; set; }

  [Parameter]
  private string ButtonText { get; set; } = "Show object's data";

  string _buttonText;

  string _objectAsJson = "";

  public void DumpVMToConsole()
  {
    _objectAsJson = GetObjectAsFormattedJson(ObjectToDump);
    Console.WriteLine(_objectAsJson);
  }

  public string GetObjectAsFormattedJson(object obj)
  {
    return JsonConvert.SerializeObject(
      value: obj, 
      formatting: Formatting.Indented, 
      settings: new JsonSerializerSettings
      {
        PreserveReferencesHandling = PreserveReferencesHandling.Objects
      });
  }

}

然后将其粘贴在 Blazor 页面的某个位置,如下所示:

<ObjectDumper ObjectToDump="@YourObjectToVisualise" />

然后呈现一个按钮,您可以按下以查看绑定对象的当前值:

在此处输入图像描述

我已将其保存在 GitHub 存储库中:tomRedox/BlazorObjectDumper

于 2019-05-26T07:27:22.870 回答