为什么object.ToString()存在?

时间:2009-10-13 17:07:35

标签: c# .net object

拥有IStringable界面不是更优雅和整洁吗?

谁需要这个Type.FullName对象返回给我们?

编辑:每个人都在问为什么我觉得它更优雅..

嗯,就像那样,对象将使用CompareTo方法,而不是IComparable,默认情况下抛出异常或返回0。

有些对象不能也不应该被描述为字符串。对象可以同样返回string.EmptyType.FullName只是一个随意的选择..

对于Console.Write(object)之类的方法,我认为它应该是:Write(IStringable)。

但是,如果你将WriteLine用于除字符串之外的任何东西(或其ToString很明显的东西,如数字),在我看来它只适用于调试模式..

顺便说一下 - 我该怎么评论你们所有人?我发布答案是否可以?

12 个答案:

答案 0 :(得分:19)

让Object.ToString使得Console.WriteLine之类的API成为可能。

从设计角度来看,BCL的设计者认为提供实例的字符串表示的能力应该对所有对象都是通用的。真正的完整类型名称并不总是有用,但他们觉得在根级别具有可自定义表示的能力超过了在输出中看到完整类型名称的轻微烦恼。

如果没有Object.ToString,您可以实现Console.WriteLine,而是执行接口检查,如果接口不存在,则默认为该类型的全名。但是,每个想要捕获对象实例的字符串表示的API都必须实现此逻辑。考虑到在核心BCL中使用Object.ToString的次数,这将导致大量重复。

答案 1 :(得分:19)

有三种虚拟方法恕我们应该从未添加到System.Object ...

  • 的ToString()
  • GetHashCode()方法
  • 等于()

所有这些都可以按照您建议的界面实施。如果他们这样做了我认为我们会好得多。那么为什么这些问题呢?我们只关注ToString():

  1. 如果ToString()应该由使用ToString()的人实现并显示结果,那么您将拥有编译器无法强制执行的隐式契约。你假设ToString()被重载了,但没有办法强迫它出现这种情况。
  2. 使用IStringable,您只需要将其添加到通用类型约束或从中派生您的接口,以要求它在实现对象时使用。
  3. 如果您在重载ToString()时发现的好处是针对调试器,则应该开始使用[System.Diagnostics.DebuggerDisplayAttribute]。
  4. 至于需要通过String.Format()和/或Console.WriteLine将对象转换为字符串的实现,它们可能已延迟到System.Convert.ToString(对象)并检查类似'IStringable'的内容,如果没有实现,则会失败到类型的名称。
  5. 正如Christopher Estep所指出的那样,它具有特定的文化特征。
  6. 所以我想我一个人站在这里说我讨厌System.Object及其所有虚拟方法。但我确实喜欢C#作为一个整体而且整体而言我认为设计师做得很好。

    注意:如果您打算依赖于ToString()的重载行为,我建议您继续定义您的IStringable接口。不幸的是,如果你真的想要它,你将不得不为该方法选择另一个名称。

    更多

    我的同事和我刚刚谈到这个话题。我认为ToString()的另一个大问题是回答“它用于什么?”的问题。是显示文字吗?序列化文字?调试文字?完整型名称?

答案 2 :(得分:3)

我认为它存在是因为它对所有对象都是一个非常方便的东西,并且不需要使用add'l cruft。为什么你认为IStringable会更优雅?

答案 3 :(得分:3)

完全没有。

不需要实施它会返回特定于文化的结果。

  

此方法返回对文化敏感的人类可读字符串。例如,对于值为零的Double类的实例,Double .. ::。ToString的实现可能会返回“0.00”或“0,00”,具体取决于当前的UI文化。

此外,虽然它有自己的实现,但可以覆盖,通常是。

答案 4 :(得分:1)

为什么要让它变得更复杂?它现在的方式基本上确定每个对象都能够将其值打印到字符串,我看不出有什么问题。

答案 5 :(得分:1)

嗯,所以它可以在派生类中被覆盖吗?

答案 6 :(得分:0)

“可串行”表示在很多场景中都很有用,库设计者可能认为ToString()更直接。

答案 7 :(得分:0)

使用IStringable,您将需要进行额外的检查/强制转换,以查看是否可以以字符串格式输出对象。对于这样一个普通的操作而言,这对于性能的影响太大了,无论如何对于99.99%的所有对象都应该是一件好事。

答案 8 :(得分:0)

Structs和Objects都有ToString()成员,以便于调试。

最简单的示例可以在Console.WriteLine中看到,它接收包括对象在内的整个类型列表,但也接收params object[] args。由于Console通常是TextWriter的一个层,因此在写入文件和其他流(套接字)时,这些语句也很有用(有时)。

它还说明了一个简单的面向对象设计,它表明您不应该仅仅因为可以创建接口。

答案 9 :(得分:0)

我的新基类:

class Object : global::System.Object
{
    [Obsolete("Do not use ToString()", true)]
    public sealed override string ToString()
    {
        return base.ToString();
    }

    [Obsolete("Do not use Equals(object)", true)]
    public sealed override bool Equals(object obj)
    {
        return base.Equals(this, obj);
    }

    [Obsolete("Do not use GetHashCode()", true)]
    public sealed override int GetHashCode()
    {
        return base.GetHashCode();
    }
}

答案 10 :(得分:0)

答案 11 :(得分:-1)

我想补充一些关于为什么.NET的System.Object类定义具有ToString()方法或成员函数的想法,以及之前在调试时发布的帖子。

由于.NET公共语言运行时(CLR)或执行运行时支持Reflection,因此能够在给定类类型的字符串表示的情况下实例化对象似乎是必不可少且基本的。如果我没弄错的话,CLR中的所有引用值都是从System.Object派生的,类中的ToString()方法通过Reflection确保其可用性和用法。在.NET中定义类时,定义和实现IStringable接口并不是必需的,也不是必需的,并且无法确保在查询程序集以查找其支持的类类型后动态创建新实例的能力。

由于2.0,3.0和3.5运行时提供的更高级的.NET功能(如Generics和LINQ)基于Reflection和动态实例化,更不用说.NET允许的.NET动态语言运行时(DLR)支持能够通过字符串类型识别和创建实例的脚本语言(如Ruby和Python)的实现似乎是所有类定义中必不可少的函数。

简而言之,如果我们无法识别和命名我们想要实例化的特定类,我们如何创建它?依赖于ToString()方法,该方法具有将类类型作为“人类可读”字符串返回的基类行为,这似乎是有道理的。

也许对Jeffrey Ricther和Don Box关于.NET Framework设计和架构的文章和书籍的评论也可以提供关于这个主题的更好的见解。