2012-04-23 100 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