C#:应该如何实现ToString()?

问题是:

  • GUI库喜欢使用ToString作为类的默认表示。 它需要本地化。
  • ToString用于记录。 它应该提供与编程相关的信息,不翻译并包括内部状态,如代理键和枚举值。
  • ToString被许多字符串操作使用,这些操作在写入流时将对象作为参数,例如String.Format 。 根据您认为不同的上下文。
  • 如果同一对象有许多不同的表示, ToString太有限了,例如。 长短forms。

由于使用的不同,有许多不同的实现方式。 所以它们太不可靠而不是真正有用。

应该如何实现ToString才有用? 什么时候应该使用ToString ,什么时候应该避免?


.NET Framework文档说:

此方法返回一个对文化敏感的人类可读字符串。

有一个类似的问题 ,但不一样。

看起来你对一个小小的方法有很大的期望:)据我所知,在很多不同的上下文中使用一般方法并不是一个好主意,特别是当它的行为因类而异。

这是我的建议:

1.不要让GUI库使用对象的ToString()。而是使用更有意义的属性(几乎所有控件都可以自定义以显示除ToString之外的其他属性),例如使用DisplayMember。 2.当获取有关对象的某些信息(用于记录或其他用法)时,让某人决定(另一个对象或对象本身)应该提供什么以及应该如何显示它。(策略模式可能派上用场)

这是一篇很好的文章,它解释了Overriding System.Object.ToString()和实现IFormattable

这取决于你class级的入学用法。 许多类没有自然的字符串表示(即Form对象)。 然后我将实现ToString作为一个信息丰富的方法(表单文本,大小等)在调试时很有用。 如果该类旨在向用户提供信息,那么我将实现ToString作为该值的默认表示。 例如,如果你有一个Vector对象,那么ToString可能会将向量作为X和Y坐标返回。 如果还有其他方法来描述类,我还会在这里添加替代方法。 因此,对于Vector,我可能会添加一个方法,将描述作为角度和长度返回。

出于调试目的,您可能还需要将DebuggerDisplay属性添加到您的类中。 这告诉我们如何在调试器中显示类,但它不会影响字符串表示。

您可能还需要考虑使ToString返回的值可解析,以便您可以从字符串表示创建对象。 就像你可以用Int32.Parse方法一样。

需要考虑的另一个问题是ToString和Visual Studio的调试器之间的紧密集成。 Watch窗口显示ToString的结果作为表达式的值,因此如果您的方法执行任何延迟加载,有任何副作用或需要很长时间,那么您可能会看到奇怪的行为或调试器可能看起来挂起。 当然,这些品质不是精心设计的ToString方法的标志,但它们会发生(例如,天真的“从数据库中获取翻译”实现)。

因此,我认为默认的ToString方法(没有参数)是Visual Studio调试钩子 – 暗示它通常不应该被重载以供程序在调试上下文之外使用。

虽然知道的人利用调试属性(DebuggerTypeProxyAttribute,DebuggerDisplayAttribute,DebuggerBrowsableAttribute)来自定义调试器,但许多人(包括我自己)通常认为ToString生成的默认输出并在Watch窗口中显示为足够好。

我理解这是一个相当严格的观点 – 将ToString写成调试器钩子 – 但我发现实现IFormattable似乎是更可靠和可扩展的路径。

就个人而言,我不经常实现ToString。 在许多情况下,它没有多大意义,因为类型的主要作用可能是定义行为,而不是数据。 在其他情况下,它无关紧要,因为没有客户需要它。

在任何情况下,这里有一些有意义的情况(不是详尽的清单):

  • 如果可以想象ToString的结果被解析回该类型的实例而没有数据丢失。
  • 当类型具有简单(即不复杂)的值时。
  • 当该类型的主要目的是将数据格式化为文本。

我不同意您列出的使用方案之间存在冲突。 当显示是主要目的时,ToString应提供用户友好的文本,但是对于日志记录(或者更确切地说,正如您描述的那样,用于跟踪),我会说在任何情况下都不应该跟踪特定于UI的元素,而是一个目的是编写详细的跟踪数据的对象。

所以没有冲突,因为根据单一责任原则,它不应该是同一类型。

请记住,如果需要更多控制,可以始终重载ToString方法。