为什么/何时适当覆盖ToString?

我在研究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; } 
  • 你需要重写ToString吗? 没有。

  • 你能以另一种方式获得对象的string表示吗? 是。

但是通过使用ToString您正在使用一种对所有对象都通用的方法,因此其他类也知道这个方法。 例如,每当.NET框架想要将对象转换为string表示forms时, ToString就是一个主要的候选对象(如果你想提供更复杂的格式化选项,还有其他的)。

具体而言,

 Console.WriteLine(yourObject); 

会调用yourObject.ToString()

我只是直接从.NET开发系列的框架devise指南给你答案。

避免ToString 引发exception

考虑返回与实例关联的唯一string。

考虑ToString的输出作为此types的任何parsing方法的有效input。

确保ToString没有明显的副作用。

只有在要求适当的许可后,才能通过覆盖ToString来报告安全敏感信息。 如果权限需求失败,则返回一个不包含安全敏感信息的string。

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

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

一个友好的名字,而不是一个独特的,但不可读的ID。

同样值得一提的是,Chris Sells在准则中解释说, ToString对用户界面经常是危险的。 一般来说,我的经验法则是公开一个属性,将用于绑定信息到用户界面,并保留ToString覆盖显示诊断信息给开发人员。 你也可以用DebuggerDisplayAttribute来修饰你的types。

尽量保持从ToString返回的string短。 debugging器使用ToString获取要显示给开发人员的对象的文本表示forms。 如果string比debugging器可以显示的长,debugging经验就会受到阻碍。

当返回与文化相关的信息时,基于当前线程文化进行string格式化。

如果从ToString返回的string是文化敏感的或者有各种方式来格式化string,请提供ToString(string format)重载或实现IFormattable 。 例如, DateTime提供了重载并实现了IFormattable

不要ToString返回空string或null

我发誓遵守这些准则,你应该。 我不能告诉你我的代码是如何通过ToString这个指导来改进的。 像IEquatable(Of T)IComparable(Of T) 。 这些东西使你的代码非常实用,你不会为了实现它而花费额外的时间。

就个人而言,我从来没有真正使用过ToString的用户界面,我总是暴露一些属性或方法。 大多数情况下,您应该使用ToString来进行debugging和开发。 用它来显示重要的诊断信息。

重载ToString()允许给出一个有用的可读的string表示forms的类。

这意味着输出可以显示有关您的课程的有用信息。 例如,如果你有一个Person类,你可能会select使用ToString()输出这个人的ID,他们的名字,他们的姓氏等。这在debugging或logging时非常有用。

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

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

更好的问题是问:

为什么会覆盖ToString()?

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

像其他人提到的一样,考虑使用ToString()输出的内容很重要,因为它可以被debugging器或其他系统使用。

我喜欢将ToString方法想象为对象的–help参数。 它应该简短,可读,明显,易于显示。 它应该显示对象不是它所做的 。 考虑到这一切,让我们考虑…

使用案例 – parsingTCP数据包:

不是只有应用程序级别的networking捕获,而是像pcap捕获一样具有更多肉的东西。

您只想为TCP层重载ToString(),以便将数据打印到控制台。 它将包括什么? 你可能疯了,并parsing所有的TCP细节(即TCP是复杂的)…

其中包括:

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

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

公开人们期望看到的内容:

  • 源端口
  • 目的端口

我更喜欢一个合理的输出,这对于人类来说很容易parsing,但是YMMV 。

 TCP:[destination:000, source:000] 

没有什么复杂的,输出是不是机器parsing(即除非人们滥用您的代码),其目的是为了人类的可读性。

但是我之前提到的那些多汁信息的其余部分呢,是不是也有用呢? 我会得到,但首先…


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

有两个原因:

  1. 人们不明白ToString()的作用
  2. 基础“对象”类缺less另一个同样重要的string方法。

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

很多人使用ToString()来拉对象的简单string表示。 C#手册甚至指出:

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

显示,而不是进一步处理。 这并不意味着,拿上面的TCP数据包的漂亮的string表示,并使用正则expression式:: cringe ::来拉动源端口。

正确的做法是直接在SourcePort属性上调用ToString()(这是一个简单的例子,所以ToString()应该已经可用了)。

如果您需要更强大的function来打包复杂对象的状态以进行机器分析,则最好使用结构化序列化策略。

幸运的是,这样的策略非常普遍:

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

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

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

我还没有看到一个实现这个核心的语言,但是我已经看到并使用了这种方法的变种。

其中一些包括:

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

基本上,TCP数据包状态的毛茸茸的混乱应该被描述为人的可读性。 为了避免谈论TCP的“打死马”,我会在“#1”的情况下“点一个手指”,我认为ToString()和ToVerboseString()未被充分利用。

使用案例 – 数组:

如果你主要使用一种语言,你可能会习惯这种语言的方法。 对于像我这样在不同语言之间跳跃的人来说,多种多样的方法可能会令人不快。

也就是说,这让我恼火的次数大于每个印度教神的所有手指总和的总和。

有各种各样的情况下,语言使用常见的黑客和一些 正确的 。 有些需要轮子重新发明,有些做浅倾,有的则倾倒,没有一个按照我希望的方式工作。

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

 print(array.ToString()); 

输出:“Array [x]”或“Array [x] [y]”

其中x是第一维中的项目数,y是第二维中的项目数,或者是指示第二维是锯齿状的某个值(最小/最大范围也许是?)。

和:

 print(array.ToVerboseString()); 

由于我欣赏美丽的东西,所以输出整个她的声音很漂亮。

希望这个话题能让我长时间感到厌恶。 至less我给PHPers撒了一点点巨魔诱饵,以此来回答这个问题。

这是关于任何事情的良好实践,真的。

ToString()在许多地方被用来返回一个对象的string表示,一般供人类使用。 通常可以使用相同的string来重新水化对象(例如,考虑intDateTime ),但这并不总是一个给定的(例如,一棵树可能有一个有用的string表示,它只是显示一个Count,但显然你可以'用它来重build它)。

特别是debugging器将使用这个在监视窗口,即时窗口等显示variables,因此ToString对于debugging实际上是无价的。

一般来说,这样的types通常也会有一个返回string的显式成员。 例如,Lat / Long对可能有ToDecimalDegrees ,例如返回"-10, 50" ToDegreesMinutesSeconds "-10, 50" ,但也可能有ToDegreesMinutesSeconds ,因为这是Lat / Long对的另一种格式。 同样的types也可以覆盖ToString ,其中一个为debugging提供了一个“默认”,甚至可能用于渲染网页等(例如,Razor中的@构造将ToString()结果写入非-stringexpression式到输出stream)。

object.ToString()将对象转换为其string表示forms。 如果你想改变用户在你创build的类上调用ToString()时返回的内容,那么你需要重写该类中的ToString()

如果你不重写ToString那么你得到你的基类的实现,对于Object来说只是类的简短types名称。

如果你想要一些其他的,更有意义或有用的ToString实现,然后覆盖它。


当使用Listtypes的List作为ListBox的数据源时,这会很有用,因为ToString会自动显示。

当你想将你的types传递给String.Format ,就会出现另一个问题,它调用ToString来获取types的表示。

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

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

  • 请记住,出于debugging目的,您可以依靠DebuggerDisplayAttribute 。 你可以在这里阅读更多。

  • 通常,在POCO上,你总是可以覆盖ToString() 。 POCO是数据的结构化表示,通常可以成为一个string。

  • deviseToString是你的对象的文本表示。 也许它的主要领域和数据,可能是在集合中有多less项目的描述等等。

  • 总是尝试将该string合并到一行中,只有重要的信息。 如果您有一个具有姓名,地址,号码等属性的Person类别,则只返回主要数据(姓名一些ID号码)。

  • 小心不要重写ToString()一个好的实现。 一些框架类已经实现了ToString() 。 重写这个默认实现是一件坏事:人们会期待从ToString()得到一个特定的结果,并得到另一个结果。

不要害怕使用ToString() 。 我唯一要小心的是返回敏感信息。 除此之外,风险很小。 当然,正如一些人指出的,其他类将使用您的ToString时,获得信息。 但是, 什么时候返回types名称会比获得一些实际的信息更好?

没有人提到的东西呢:通过重写ToString() ,你也可以考虑重写ToString(string Formatter)所以你可以这样做:

  public override ToString() { string strOut = string.Format("{0,-20} {1, -20}", m_work, m_personal); return strOut; } public override ToString(string formatter) { string strOut = this.ToString(); switch (formatter.ToLower()) { case "w": strOut = m_Work; break; case "p": strOut = m_Personal; break; case "hw": strOut = string.Format("mailto:{0}", m_Work); break; } return strOut; } 

这可能是有用的。

在某些情况下,可以更轻松地在debugging器监视窗口中读取自定义类的值。 如果我确切地知道我希望在监视窗口中看到什么,那么当我用这些信息覆盖ToString时,我就会看到它。

覆盖ToString()的一个好处是Resharper的工具支持:Alt + Ins – >“格式化成员”,并为您写入ToString()。

在定义结构(有效的用户原语)时,我发现最好有匹配的ToStringParseTryParse方法,特别是XML序列化。 在这种情况下,您将把整个状态转换为一个string,以便以后可以读取。

类然而更复杂的结构,通常会使用ToStringParse太复杂。 他们的ToString方法,而不是保存整个状态,可以是一个简单的描述,帮助你识别他们的状态,就像一个名字或ID的唯一标识符,或者一个列表的数量。

另外,正如Robbie所说的,覆盖ToString允许你在一个引用上调用ToString ,就像typesobject

当你有一个对象没有直觉意义的string表示的对象时,你可以使用它。 所以如果你需要打印这个人,你可以使用这个覆盖来准备它的格式。

Object.ToString方法只能用于debugging目的。 默认实现显示的对象types名称不是很有用。 考虑重写此方法以提供更好的诊断和debugging信息。 请考虑日志基础架构通常也使用ToString方法,因此您可以在日志文件中find这些文本片段。

不要Object.ToString方法中返回本地化的文本资源。 原因是ToString方法应该总是返回一些开发人员可以理解的东西。 开发者可能不会说应用程序支持的所有语言。

当你想返回一个用户友好的本地化文本时, 实现 IFormattable接口。 这个接口用参数formatformatProvider定义一个ToString重载。 formatProvider帮助您以文化意识的方式来设置文本的格式。

另见: Object.ToString和IFormattable

简单取决于你的财产将如何使用。 如果你只需要一次格式化string,那么它并没有超出它的意义。

但是,您似乎重写了ToString方法,不会返回属性的普通string数据,而是执行标准的格式化模式。 由于您正在使用带有填充的string.format。

因为你说你在学习,所以这个练习似乎也碰到了关于封装和代码重用的面向对象编程的核心原则。

string.format采用你为填充设置的参数,确保每次调用该代码的属性的格式都是相同的。 同样,前进你只需要在一个地方而不是多个地方改变它。

伟大的问题,也是一些很好的答案!

我发现在实体类上重写ToString方法很有用,因为它有助于快速识别testing中的问题,特别是在断言失败的情况下,testing控制台将调用对象上的ToString方法。

但是,与之前所说的一致,就是要提供一个人类可读的对象。