2012-04-23 101 views
92

我正在研究C#,我想知道覆盖ToString的重点和好处是什么,如下例所示。为什么/何时适当覆盖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; 
} 
+4

取决于如果你真的想用它来随时随地在UI中显示的对象,否则它通常只是用于调试 - 你会看到在VS的监视窗口中的ToString输出。 (但是你也可以通过类上的属性来实现它。)假设你有标题和输出,它看起来像这个程序使用它来使用Console.WriteLine(obj.GetToStringItemsHeadings)转储对象。 Console.WriteLine(obj);'或类似的。 – Rup 2012-04-23 09:38:48

+2

我真的不明白这个问题。它可以做不同的事情吗?是。但是,你为什么要*以不同的方式做。 – 2012-04-23 09:38:49

+5

我真的会跳过属性名称中的GetToString ...然后你会得到例如'Console.WriteLine(obj.ItemHeadings)' – Svish 2012-04-23 12:09:48

回答

123
  • 您需要覆盖ToString

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

但是,通过使用ToString您使用的是通用的方法来所有对象,因此其他类知道这个方法。例如,每当.NET框架想要将对象转换为字符串表示形式时,ToString就是一个主要候选对象(如果您想提供更详细的格式选项,还有其他方法)。

具体地说,

Console.WriteLine(yourObject); 

将调用yourObject.ToString()

+12

是的。这在MVC或ASP.Net开发中非常有用,其中'@ yourObject'和'<%= yourObject%>'将会是“ToString-ed”。 – 2012-04-23 14:23:26

+3

当填充组合框时,ToString是获取项目文本的默认调用 – 2012-04-25 02:59:45

+3

请注意这种做法。 真实故事:学生用除了返回字符串之外的方法重写ToString,改变了数据。他正在调试这个程序,但是当程序站在断点处时,值不断变化。显然 - 每次他检查值ToString被执行 - 所以即使程序没有运行,值也会改变。 – JNF 2012-05-03 14:22:32

39

覆盖ToString()允许您给出一个有用的可读的字符串表示形式的类。

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

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

5

如果你不覆盖ToString那么你得到你的基类实现,其中Object只是类的简短类型名称。

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


这可以使用你的类型作为数据源的ListBoxToString列表时,会自动显示是有用的。

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

6

object.ToString()将对象转换为其字符串表示形式。如果您想更改用户在您创建的课程上呼叫ToString()时返回的内容,那么您需要在该课程中覆盖ToString()

9

这是关于良好的做法,尽可能多的东西,真的。

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

特别是调试器将使用它来在监视窗口,即时窗口等中显示变量,因此ToString对于调试实际上是无价的。

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

122

我只是直接从.NET Development Series的Framework Design Guidelines给你答案。从ToString

AVOID抛出异常考虑返回与实例相关联的唯一的字符串。

CONSIDER输出为ToString是此类型的任何解析方法的有效输入。

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

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

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

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

DO喜欢在一个唯一但不可读的ID上使用友好名称。

它也值得一提,因为Chris Sells也在指导中解释了ToString对用户界面经常是危险的。通常,我的经验法则是将用于绑定信息的属性暴露给用户界面,并且保留ToString覆盖,以便向开发人员显示诊断信息。你也可以用DebuggerDisplayAttribute来修饰你的类型。

DO尽量保持从ToString短的返回字符串。调试器使用ToString来获取要显示给开发人员的对象的文本表示形式。如果字符串比调试器可以显示的长,则调试体验受阻。

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

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

切勿回报从ToString

我通过这些准则发誓一个空字符串或空的,你应该给。我无法告诉你我的代码如何通过ToString的这一条指南得到改善。对于像IEquatable(Of T)IComparable(Of T)这样的东西也是一样的。这些东西让你的代码非常实用,你不会为了实现它而花费额外的时间。

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

+5

好的答案,是这些吗?您引用的指南http://msdn.microsoft.com/en-us/library/ms229042.aspx? – Jodrell 2012-04-23 14:14:46

+1

@Jodrell我相信这取自[框架设计指南](http://www.amazon.com/框架设计指南公约-libraries/dp/0321545613) – 2012-04-23 15:11:36

+0

Jim是正确的,这些都来自框架设计指南,这是MSFT用来开发他们的托管API的指南,我强烈推荐购买这本书,因为它会改变方式你需要设计你的软件并生成高质量的代码 – 2012-04-23 17:33:11

1

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

然而类别更多的化合物结构通常对于使用ToStringParse来说太复杂。他们的ToString方法不是保存整个状态,而是一个简单的描述,它可以帮助您识别其状态,例如像名称或ID之类的唯一标识符,或者可以是列表的数量。

此外,正如罗比所说,覆盖ToString允许您致电ToString上的基本参考为object

2

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

2

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

1

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

0

简单取决于您的财产将如何使用。如果你只需要对字符串进行一次格式化,那么它就不会超越它。

但是,看起来您正在重写ToString方法以不返回属性的普通字符串数据,而是执行标准格式模式。由于您正在使用带填充的string.format。

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

将您为填充设置的参数设置为string.format可确保每次调用该属性时都会以相同方式对该属性进行格式化。同样,前进你只需要在一个地方而不是很多地方改变它。

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

4

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

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

  • 请记住,出于调试目的,您可以依靠DebuggerDisplayAttribute。你可以阅读更多关于它here

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

  • 设计ToString是您的对象的文本表示。也许它的主要领域和数据,可能是集合中有多少物品的描述等。

  • 总是尝试将该字符串合并到一行中,并且只有重要信息。如果您有名称,地址,号码等属性的Person类,则只返回主数据(指定一些ID号)。

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

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

12

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

一个更好的问题会是什么问:

为什么一个重写的ToString()?

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

和其他人一样,考虑什么你用ToString()输出是很重要的,因为它可以被调试器或其他系统使用。

我喜欢将ToString方法想象成对象的--help参数。它应该是简短的,可读的,明显的,并且易于显示。它应该显示什么对象而不是它确实。所有这一点让我们考虑一下......

使用案例 - 解析TCP包:

而不是应用级别唯一的网络捕获但更像是一个PCAP捕获肉的东西。

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

其中包括:

  • 源端口
  • 目标端口
  • 序列号
  • 确认编号
  • 数据偏移量
  • 标志
  • 窗口胶印
  • 校验
  • 紧急指针
  • 选项(我不甚至要去那里)

但是你想接收所有的垃圾,如果你分别致电TCP.ToString( )100个数据包?当然不会,这会造成信息超载。最简单的和显而易见的选择,也是最明智的...

揭露什么人希望看到:

  • 源端口
  • 目标端口

我喜欢懂事输出对于人类来说很容易解析,但是YMMV

TCP:[destination:000, source:000] 

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

但是我之前提到过的那些多汁信息的其余部分怎么样也没有用? )我会到,但第一...


的ToString(的所有时间

最有价值的和未充分利用的方法之一,有两个原因:

  1. 人不不明白ToString()是什么
  2. 基础'对象'类缺少另一个同样重要的字符串方法。

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

很多人使用的ToString()拉一个对象的简单字符串表示。 C#手册甚至规定:

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

显示,没有进一步处理。这并不意味着,拿我上面的TCP数据包的漂亮的字符串表示,并使用正则表达式:: cringe ::来拉取源端口。

right做事情的方法是,直接在SourcePort属性上调用ToString()(它是一个ushort,所以ToString()应该已经可用)。

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

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

  • ISerializable的(C#)
  • 泡菜(蟒蛇)
  • JSON(JavaScript或实现任何语言)
  • SOAP
  • 等...

注意:U您正在使用PHP,因为HERP-DERP,还有为::傻笑::

原因2的功能nless - toString()方法是不够的:

我还没有看到一个语言以此为核心,但我已经在野外看到并使用了这种方法的变体。其中一些

包括:

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

基本上,应该人类要描述的TCP数据包的状态的那毛状乱七八糟可读性。为了避免“白费口舌”谈到TCP在#1情况下,我认为toString()和ToVerboseString()没有得到充分利用我“点手指” ......

使用案例 - 阵列:

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

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

various箱子地方语言使用普通hacksfewgetright。一些需要轮子重新发明,一些做浅转储,其他人做深转储,没有一个按照我希望他们的方式工作...

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

​​

输出: '数组[X]' 或 '阵列[X] [Y]'

其中x是物品的在第一维和y的数量是多少第二维中的项目或表示第二维为锯齿状的某个值(最小/最大范围可能?)。

和:

print(array.ToVerboseString()); 

输出整她,一鼓作气漂亮地打印,因为我很欣赏漂亮的东西。

我们希望,这揭示了已经惹恼了我很长一段时间的话题的一些情况。至少我为PHPers撒了一点点巨魔诱饵来降低这个答案。

+0

您写道,“我还没有看到一种实现此核心的语言”。在我看来,Python非常接近这个;例如打印数组可以简洁地输出所有数据。这是我在C#/ Java中错过的一件事,但我确实喜欢它们的严谨性。而当你需要超越ToString()时,有一点像Python的列表解析语法是很好的;我猜string.Join()是相似的,虽然不太灵活。 – 2013-09-25 09:39:40

+1

@JCoombs我并不反对,理解力很强。通过理解遍历Python中的数据结构使得生活变得更容易,但是这种方法仍然需要对对象内部结构的深入了解。从外部库导入的类并不总是显而易见的。库作者重写ToString()并提供有用的人类可读表示是一种很好的做法,但是也可以使用通用转储方法以通用结构化人类可读格式(例如JSON)输出对象结构。 – 2013-09-26 16:13:23

+0

优秀点。因此,除了基本上只显示一个typeof外,它可能会自动序列化为类似JSON的内容。 (到目前为止,我只看到.NET对象序列化为XML,但我是.NET新手)但是那么危险可能是将ToString()视为机器可读的诱惑? (例如,希望能够反序列化它。) – 2013-09-27 19:15:16

0

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

但与之前所说的一致,它是给人们可读的对象的表示。

3

东西没有人尚未提到:通过覆盖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; 
} 

哪些是有用的。

1

Object.ToString方法应仅用于调试目的。默认实现显示对象类型名称,这不是非常有用。考虑重写此方法以提供更好的诊断和调试信息。请考虑日志基础架构也经常使用ToString方法,因此您可以在日志文件中找到这些文本片段。

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

实施IFormattable接口,当你想返回一个用户友好的本地化文本。该接口使用参数formatformatProvider定义ToString超载。 formatProvider可帮助您以文化意识的方式格式化文本。

参见:Object.ToString and IFormattable