【问题标题】:Get a complete string representation of an object (like in the Immediate Window in Visual Studio)获取对象的完整字符串表示形式(如在 Visual Studio 中的即时窗口中)
【发布时间】:2011-10-05 10:13:47
【问题描述】:

给定以下示例类:

public class MyClass
{
    public string S { get; set; }
    public int I { get; set; }
    public DateTime D { get; set; }
    private float F { get; set; }
    private long l;

    public MyClass()
    {
        S = "foo";
        I = 42;
        D = new DateTime(2011, 11, 11);
        F = 3.14f;
        l = 12435;
    }
}

如果我在我的应用程序中有一个此类的实例 myClass,则在调试模式 (Visual Studio 2010) 中逐步执行代码,并在某些时候将 myClass 类型输入到即时窗口中,显示如下:

{MyClass}
    D: {11.11.2011 00:00:00}
    F: 3.14
    I: 42
    l: 12435
    S: "foo"

获取对象及其所有值的这种字符串表示形式对于日志记录非常有用。有没有一种简单易行的方法来实现这一目标?

我猜即时窗口使用反射来循环所有字段和属性,但我想我会问一下,以防万一已经存在一些实用功能或任何可以做的事情。

【问题讨论】:

标签: c# .net debugging logging


【解决方案1】:

这会将所有字段存储在字典中(确保可以首先读取它们):

public static Dictionary<string, object> GeneratePropertiesDictionary(object myClass)
{
    return myClass.GetType()
                  .GetProperties()
                  .Where(p => p.CanRead)
                  .ToDictionary(p => p.Name, p => p.GetValue(myClass, null));
}

您可以轻松地修改它以将每个名称/值附加到 StringBuilder 对象而不是字典,然后将其转储到文件中。

【讨论】:

  • 感谢您分享您的功能。我希望可能有一些可以使用的现有实用程序功能,但似乎使用反射来制作自己的实用程序是要走的路。我可能不会直接使用您的代码,但我想我会从 MSDN 的 LINQ 示例查询中制作 ObjectDumper.cs (code.msdn.microsoft.com/LINQ-Sample-Queries-13a42a54/…) 的修改版本。
【解决方案2】:

如果您想要一个对象的序列化版本,我可能会在您的日志记录中使用JavaScriptSerializer

public void LogObject(object obj)
{
    var serializer = new JavaScriptSerializer();
    var objString = serializer.Serialize(obj);

    WriteLog(objString);
}

【讨论】:

  • 如果对象可以被序列化。
  • 我在一个控制台应用程序中,所以我无权访问 JavaScriptSerializer(它说 为启用 AJAX 的应用程序提供序列化和反序列化功能。 在文档中) .
  • @Nailuj - 这可能是它适合框架的地方,但只要包含参考,它绝对可以在任何地方使用。
  • 我刚刚测试了这个,序列化时似乎没有包含私有字段/属性。这是一个不错且简单的解决方案,但正因为如此:并非完全最优。
【解决方案3】:

您可以使用反射并遍历所有字段和属性,对每个结果调用 ToString()。如果当前字段/属性是类/结构,则可以递归地执行此操作。

其次,一些类使用DebuggerDisplayAttribute,尽管您需要解析该 AFAICT。

【讨论】:

  • 谢谢 :) 但正如我在问题中所说,我认为反射是即时窗口正在使用的,但我想知道(因为我认为这对许多人有用),如果有已经存在某种实用功能来做到这一点。
  • 你要小心递归地这样做,因为你可能会陷入无限循环......
  • @Nailuj:立即窗口使用对象的默认可视化器,除非已为该类型定义了更具体的可视化器。有关可视化工具的更多信息,请参阅msdn.microsoft.com/en-us/library/zayyhzts.aspx
【解决方案4】:

如果您只想记录(即打印)对象的表示,请覆盖 ToString 方法。

ToString 是 .NET Framework 中的主要格式化方法。它将一个对象转换为它的字符串表示,以便它适合显示。

此外,如果您想提供多种输出字符串的方式(例如,支持详细或最小选项),您还可以考虑实现 IFormattable

【讨论】:

  • 是的,这当然是一种选择。但我的目标是不必为我创建的每个类重写 ToString() 方法。
  • @Nailuj - 除了覆盖 ToString 方法之外,除了使用虚拟器(仅受托管语言支持)之外,这是一种更优雅的方式来做你想做的事
  • @Ramhound:我会说这取决于。您可能经常希望 ToString 方法给出对象的“合理”表示,而不一定是所有属性。但是对于调试/记录目的,您可能需要像“ToDebugString”这样的东西来为您提供准确的信息。附带说明:为什么有人-1这个?这并不是一个错误的答案......那个人的解释会很好!
  • @Nailuj:关于想要多种形式的 ToString 的好处。我添加了关于 IFormattable 的注释,它提供了对格式化选项的支持,例如 DateTime。即使这不是你要找的答案。 ;)
  • 在大多数情况下,您尝试写入的数据类型(例如调试日志)是由第三方库定义的,因此无法直接添加 ToString() 实现。我也不确定使用扩展方法是不是一个好主意。 ToString() 用于呈现给用户,而不是调试器。 Python 在 str() 和 repr() 函数中将这两个用例分开,Rust 也有类似的区别。
猜你喜欢
  • 1970-01-01
  • 2022-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多