为什么/何时覆盖ToString是否合适?

3D-*_*tiv 102 c# overriding

我正在学习C#,我想知道重写的重点和好处是什么ToString,如下例所示.

这可以用更简单的方式完成,使用没有覆盖的常用方法吗?

public string GetToStringItemsHeadings
{
    get { return string.Format("{0,-20} {1, -20}", "Office Email", "Private Email"); }
}


public override string ToString()
{
    string strOut = string.Format("{0,-20} {1, -20}", m_work, m_personal);
    return strOut;
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*son 129

我将直接从.NET开发系列的框架设计指南中给出答案.

避免抛出异常ToString

CONSIDER返回与实例关联的唯一字符串.

ToString对于此类型的任何解析方法,CONSIDER的输出是有效输入.

DO确保ToString有没有明显的副作用.

DO通过的改写报表安全敏感信息ToString只要求苛刻的适当的权限之后.如果权限请求失败,则返回不包含安全性敏感信息的字符串.

Object.ToString方法旨在用于一般显示和调试目的.默认实现只提供对象类型名称.默认实现不是很有用,建议重写该方法.

DO覆盖ToString时可以返回一个有趣的人类可读的字符串.默认实现不是很有用,自定义实现几乎总能提供更多价值.

不要在一个独特的,但不能读取ID喜欢的友好名称.

值得一提的是,Chris Sells也在指南中解释了ToString对用户界面通常很危险的指南.通常,我的经验法则是公开一个属性,该属性将用于将信息绑定到UI,并保留ToString用于向开发人员显示诊断信息的覆盖.你也可以装饰你的类型DebuggerDisplayAttribute.

尽量保持ToString短信返回的字符串.调试器用于ToString获取要向开发人员显示的对象的文本表示.如果字符串比调试器可以显示的长,则调试体验受阻.

DO返回文化相关的信息时,基于当前线程的文化字符串格式化.

DO提供过载ToString(string format),或实现IFormattable,如果从字符串返回ToString是文化敏感或有各种方式来格式化字符串.例如,DateTime提供重载和实现IFormattable.

请勿返回空字符串或nullToString

我发誓这些指导方针,你应该这样做.我无法告诉你我的代码是如何通过这一指南改进的ToString.同样的事情也适用于IEquatable(Of T)IComparable(Of T).这些东西使您的代码非常实用,并且您不会后悔花费额外的时间来实现它们.

就个人而言,我从来没有真正用过ToString 多少用户界面,我总是暴露某种属性或方法.大多数时候您应该ToString用于调试和开发人员目的.用它来显示重要的诊断信息.

  • 它不是,但是当你引用指南时,提供源是一个不可否认的优点. (14认同)
  • 我不知道SO正在变成维基百科. (13认同)
  • 很好的答案,这些是您参考的指南http://msdn.microsoft.com/en-us/library/ms229042.aspx? (6认同)
  • 需要更好的引用. (6认同)
  • @Jodrell我相信它取自[框架设计指南](http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613) (2认同)

Kon*_*lph 127

  • 你需要覆盖ToString吗?没有.

  • 你能用另一种方式获得对象的字符串表示吗?是.

但是通过使用,ToString您使用的是所有对象共有的方法,因此其他类知道此方法.例如,每当.NET框架想要将对象转换为字符串表示时,ToString它都是主要候选者(如果您想提供更精细的格式化选项,还有其他人).

具体而言,

Console.WriteLine(yourObject);
Run Code Online (Sandbox Code Playgroud)

会调用yourObject.ToString().

  • 是.这在MVC或ASP.Net开发中非常有用,其中`@ yourObject`和`<%= yourObject%>`将是"ToString-ed". (13认同)
  • @JNF我不接受.`toString`是*意味着*被覆盖.期.对此声明提出警告并不高效.如果你做错了 - 你自己的错.事实上,你的学生在David Anderson的回答中公布的覆盖"ToString"的官方指南列表中违反了第4点. (8认同)
  • 此外,在填充组合框时,ToString是获取项目文本的默认调用 (4认同)
  • 小心这种做法.真实的故事:学生用一种方法覆盖ToString,除了返回一个字符串,还改变了数据.他正在调试该程序,但当程序站在一个断点时,价值不断变化.显然 - 每次他检查值ToString都被执行 - 所以即使程序没有运行,值也会改变. (3认同)
  • @JNF什么是"这种做法"?`ToString`实际上不应该改变对象的状态.但这不是我所倡导的. (3认同)
  • @KonradRudolph 重点是-覆盖系统功能时要小心:) (2认同)

Rob*_*ine 39

覆盖ToString()允许您提供类的有用的人类可读字符串表示.

这意味着输出可以显示有关您的类的有用信息.例如,如果你有一个Person类,你可以选择ToString()输出person的id,他们的名字,姓氏等.这在调试或记录时非常有用.

关于你的例子 - 很难判断你的覆盖是否有用而不知道这个类是什么 - 但是实现本身是可以的.


Eva*_*ice 13

这总是合适的,但要仔细考虑你所展示的背后的意图

一个更好的问题是问:

为什么会覆盖ToString()?

ToString()是进入对象状态的窗口.强调国家作为一项要求.强大的OOP语言(如Java/C#)通过将所有内容封装在一个类中来滥用OOP模型.想象一下,您使用的语言编码不遵循强大的OOP模型; 考虑您是使用类还是函数.如果您将它用作函数(即动词,动作)并且内部状态仅在输入/输出之间暂时保持,则ToString()将不会添加值.

像其他人所说的,是要考虑的重要的东西,你用的ToString(),因为它可以通过调试程序或其他系统使用的输出.

我喜欢将ToString方法想象为对象的--help参数.它应该简短,可读,明显且易于显示.它应该显示的对象是什么不是它.考虑到所有这些,我们考虑一下......

用例 - 解析TCP数据包:

不仅仅是应用程序级别的网络捕获,而是像pcap捕获更多的肉类.

您希望仅为TCP层重载ToString(),以便可以将数据打印到控制台.它包括什么?您可能会发疯并解析所有TCP细节(即TCP很复杂)......

其中包括:

  • 源端口
  • 目的端口
  • 序列号
  • 致谢号码
  • 数据偏移
  • 窗口偏移
  • 校验
  • 紧急指针
  • 选项(我至不打算去那里)

但是如果你在100个数据包上调用TCP.ToString(),你想要收到所有垃圾吗?当然不是,这将是信息过载.简单明了的选择也是最明智的......

暴露人们期望看到的东西:

  • 源端口
  • 目的端口

我更喜欢合理的输出,人类很容易解析但是YMMV.

TCP:[destination:000, source:000]
Run Code Online (Sandbox Code Playgroud)

没有什么复杂的,输出不是机器解析(即除非人们滥用你的代码),预期的目的是为了人类的可读性.

但是我之前谈到过的那些多余的信息呢,那也没那么有用吗?我会接受,但首先......


ToString()有史以来最有价值和最少使用的方法之一

有两个原因:

  1. 人们不明白ToString()的用途
  2. 基础'Object'类缺少另一个同样重要的字符串方法.

原因1 - 不要滥用ToString()的用处:

很多人使用ToString()来拉取对象的简单字符串表示.C#手册甚至指出:

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

显示,不进一步处理.这并不意味着,使用上面的TCP数据包的好字符串表示,并使用regex :: cringe ::拉取源端口.

正确的做事方式是,直接调用toString()的源端口属性(BTW是一个USHORT这样的ToString()应该已经可用).

如果您需要更强大的东西来打包复杂对象的状态以进行机器解析,那么最好使用结构化序列化策略.

幸运的是,这种策略很常见:

  • ISerializable(C#)
  • 泡菜(Python)
  • JSON(Javascript或任何实现它的语言)
  • 肥皂
  • 等等...

注意:除非你使用PHP,因为herp-derp,有一个函数::: snicker ::

原因2 - ToString()是不够的:

我还没有看到一种语言在核心实现这一点,但我已经看到并使用了这种方法的变体.

其中一些包括:

  • ToVerboseString()
  • 的ToString(详细=真)

基本上,应该描述TCP数据包状态的毛茸茸的混乱以供人类阅读.为了避免"殴打死马"谈论TCP我会'指责'在#1的情况下,我认为ToString()和ToVerboseString()未得到充分利用......

用例 - 数组:

如果您主要使用一种语言,那么您可能对该语言的方法感到满意.对于像我这样在不同语言之间跳跃的人来说,各种方法的数量可能会令人恼火.

也就是说,这激怒了我的次数大于每个印度教神的所有手指的总和.

各种地方语言使用常见的情况的黑客一些得到的权利.有些需要轮子重新发明,有些需要进行浅层转储,有些需要进行深度转储,其中没有一种按照我希望的方式工作......

我要求的是一个非常简单的方法:

print(array.ToString());
Run Code Online (Sandbox Code Playgroud)

输出:'Array [x]'或'Array [x] [y]'

其中x是第一维中的项数,y是第二维中的项数或某个值,表示第二维是锯齿状的(最小/最大范围可能是?).

和:

print(array.ToVerboseString());
Run Code Online (Sandbox Code Playgroud)

因为我欣赏漂亮的东西,所以输出整个she-bang的漂亮印刷品.

希望这能够让我对长期困扰我的话题有所了解.至少我为PHP人员撒了一个小小的诱饵,以便回答这个问题.


And*_*tan 9

这真的是关于良好的做法和任何事情.

ToString()在许多地方用于返回对象的字符串表示,通常供人类使用.通常可以使用相同的字符串来重新水化对象(想想int或者DateTime例如),但这并不总是给定的(例如树,可能有一个有用的字符串表示,只显示一个Count,但显然你不能使用那要重建它).

特别是调试器将使用它来在监视窗口,即时窗口等中显示变量,因此ToString实际上对调试非常有用.

通常,这样的类型通常也会有一个返回字符串的显式成员.例如,Lat/Long对可能会ToDecimalDegrees返回"-10, 50",例如,但它也可能有ToDegreesMinutesSeconds,因为这是Lat/Long对的另一种格式.然后,相同类型也可以覆盖ToString其中一个类型,为调试之类的内容提供"默认",甚至可能用于渲染网页等内容(例如,@Razor中的构造将ToString()非字符串表达式的结果写入输出流).


Rob*_*bie 6

object.ToString()将对象转换为其字符串表示形式.如果要更改用户调用ToString()已创建的类时返回的内容,则需要ToString()在该类中重写.


Bru*_*ant 6

虽然我认为已经提供了最有用的信息,但我将加上我的两分钱:

  • ToString()意味着要被覆盖.它的默认实现返回类型名称,虽然有时可能很有用(特别是在处理大量对象时),但在大多数情况下都不够.

  • 请记住,出于调试目的,您可以信赖DebuggerDisplayAttribute.你可以在这里阅读更多相关信息.

  • 通常,在POCO上,您始终可以覆盖ToString().POCO是数据的结构化表示,通常可以成为字符串.

  • 设计ToString是对象的文本表示.也许是它的主要领域和数据,也许是对集合中有多少项目的描述等.

  • 始终尝试将该字符串放入一行并且只包含基本信息.如果您有一个Person具有名称,地址,编号等属性的类,则仅返回主数据(名称某些ID号).

  • 注意不要覆盖良好的实现ToString().一些框架类已经实现ToString().覆盖默认实现是一件坏事:人们会期望得到某个结果ToString()并获得另一个结果.

不要真的害怕使用ToString().我唯一要注意的是返回敏感信息.除此之外,风险很小.当然,正如一些人所指出的那样,其他类在获取信息时会使用你的ToString.但是,何时返回类型名称将被认为比获得一些实际信息更好?


Jod*_*ell 5

如果你没有覆盖ToString那么你得到你的基类实现,因为Object它只是类的短类型名称.

如果你想要一些其他更有意义或更有用的实现,ToString那么就覆盖它.


当您使用类型列表作为a的数据源时,这将非常有用,ListBox因为ToString它将自动显示.

当您想要传递要String.Format调用的类型ToString以获得类型的表示时,会发生另一种情况.