webentwicklung-frage-antwort-db.com.de

Warum/wann wäre es angebracht, ToString zu überschreiben?

Ich studiere C # und frage mich, was der Sinn und Zweck des Überschreibens von ToString sein könnte, wie im folgenden Beispiel gezeigt.

Könnte dies auf eine etwas einfachere Art und Weise geschehen, indem eine übliche Methode ohne Überschreiben verwendet wird?

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;
}
99
3D-kreativ
  • Müssen Sie ToString überschreiben? Nein.

  • Können Sie eine String-Darstellung Ihres Objekts auf andere Weise erhalten? Ja.

Wenn Sie jedoch ToString verwenden, verwenden Sie eine Methode, die all objects gemeinsam ist, und daher kennen andere Klassen diese Methode. Wann immer das .NET Framework ein Objekt in eine Zeichenfolgendarstellung konvertieren möchte, ist ToString ein Hauptkandidat (es gibt andere, wenn Sie ausführlichere Formatierungsoptionen bereitstellen möchten).

Konkret 

Console.WriteLine(yourObject);

würde yourObject.ToString() aufrufen.

126
Konrad Rudolph

Ich werde Ihnen nur die Antwort direkt aus den Framework Design Guidelines aus der .NET Development Series geben. 

VERMEIDEN, DASS Ausnahmen von ToString auslöst

CONSIDER gibt eine eindeutige Zeichenfolge zurück, die der Instanz zugeordnet ist.

BETRACHTET mit der Ausgabe von ToString eine gültige Eingabe für alle Analysemethoden für diesen Typ.

DO stellt sicher, dass ToString keine beobachtbaren Nebenwirkungen hat.

DO melden sicherheitsrelevante Informationen durch eine Überschreibung von ToString nur, wenn eine entsprechende Berechtigung angefordert wird. Wenn die Berechtigungsanforderung fehlschlägt, geben Sie eine Zeichenfolge mit Ausnahme sicherheitsrelevanter Informationen zurück.

Die Object.ToString-Methode ist für allgemeine Anzeige- und Debugging-Zwecke vorgesehen. Die Standardimplementierung gibt einfach den Objekttypnamen an. Die Standardimplementierung ist nicht sehr nützlich und es wird empfohlen, die Methode zu überschreiben.

DO überschreibt ToString, wenn ein interessanter, von Menschen lesbarer String zurückgegeben werden kann. Die Standardimplementierung ist nicht sehr nützlich, und eine benutzerdefinierte Implementierung kann fast immer mehr Wert bieten. 

DO zieht einen Anzeigenamen einer eindeutigen, aber nicht lesbaren ID vor. 

Es ist auch erwähnenswert, wie Chris Sells in den Richtlinien auch erklärt, dass ToString für Benutzeroberflächen oft gefährlich ist. Im Allgemeinen besteht meine Faustregel darin, eine Eigenschaft bereitzustellen, die zum Binden von Informationen an die Benutzeroberfläche verwendet wird, und die Überschreibung ToString für die Anzeige von Diagnoseinformationen dem Entwickler zu überlassen. Sie können Ihren Typ auch mit DebuggerDisplayAttribute dekorieren.

DO versucht, die von ToString zurückgegebene Zeichenfolge kurz zu halten. Der Debugger verwendet ToString, um eine Textdarstellung eines Objekts abzurufen, die dem Entwickler angezeigt werden soll. Wenn die Zeichenfolge länger ist, als der Debugger anzeigen kann, wird die Debugging-Erfahrung behindert.

DO - Stringformatierung basierend auf der aktuellen Thread-Kultur, wenn kulturabhängige Informationen zurückgegeben werden.

DO stellt Überladung ToString(string format) bereit oder implementiert IFormattable, wenn die von ToString zurückgegebene Zeichenfolge kulturabhängig ist oder es verschiedene Möglichkeiten gibt, die Zeichenfolge zu formatieren. Zum Beispiel stellt DateTime die Überladung bereit und implementiert IFormattable

DO NOT gibt eine leere Zeichenfolge oder Null aus ToString zurück.

Ich schwöre auf diese Richtlinien, und Sie sollten es tun. Ich kann Ihnen nicht sagen, wie sich mein Code gerade durch diese eine Richtlinie für ToString verbessert hat. Das Gleiche gilt für Dinge wie IEquatable(Of T) und IComparable(Of T). Diese Dinge machen Ihren Code sehr funktionell und Sie werden es nicht bereuen, die zusätzliche Zeit für die Implementierung von etwas zu nehmen.

Persönlich habe ich ToStringmuch nie wirklich für Benutzeroberflächen verwendet. Ich habe immer eine Eigenschaft oder eine Methode irgendeiner Art verfügbar gemacht. Die meiste Zeit sollten Sie ToString für Debugging- und Entwicklerzwecke verwenden. Verwenden Sie es, um wichtige Diagnoseinformationen anzuzeigen.

127
David Anderson

Durch das Überschreiben von ToString() können Sie eine nützliche, für Menschen lesbare Zeichenfolgendarstellung einer Klasse angeben.

Dies bedeutet, dass die Ausgabe nützliche Informationen über Ihre Klasse enthalten kann. Wenn Sie beispielsweise über eine Person-Klasse verfügen, können Sie auswählen, dass ToString() die ID der Person, ihren Vornamen, ihren Nachnamen usw. ausgibt. Dies ist äußerst hilfreich beim Debuggen oder Protokollieren.

In Bezug auf Ihr Beispiel - es ist schwierig zu sagen, ob Ihre Überschreibung nützlich ist, ohne zu wissen, was diese Klasse ist -, aber die Implementierung selbst ist in Ordnung.

39
Rob Levine

Es ist immer angemessen, aber überlege genau, welche Absichten dahinter stehen

Eine bessere Frage wäre:

Warum sollte man ToString () überschreiben?

ToString () ist das Fenster in den Status eines Objekts. Betonung auf Zustand als Voraussetzung. Starke OOP Sprachen wie Java/C # missbrauchen das OOP Modell, indem sie alles in einer Klasse einkapseln. Stellen Sie sich vor, Sie codieren in einer Sprache, die nicht dem starken OOP -Modell entspricht. Überlegen Sie, ob Sie eine Klasse oder eine Funktion verwenden möchten. Wenn Sie es als Funktion (dh Verb, Aktion) verwenden und der interne Status nur vorübergehend zwischen Eingabe/Ausgabe beibehalten wird, bietet ToString () keinen Mehrwert.

Wie bereits von anderen erwähnt, ist es wichtig, zu berücksichtigen, dass was Sie mit ToString () ausgeben, da dies vom Debugger oder anderen Systemen verwendet werden kann.

Ich stelle mir die ToString-Methode gerne als den --help-Parameter eines Objekts vor. Es sollte kurz, lesbar, offensichtlich und leicht darstellbar sein. Es sollte anzeigen, was das Objekt ist und nicht, was es tut . In Anbetracht dessen sollten wir uns überlegen ...

Anwendungsfall - Analysieren eines TCP-Pakets:

Keine reine Netzwerkerfassung auf Anwendungsebene, sondern etwas mit mehr Fleisch wie eine PCAP-Erfassung.

Sie möchten ToString () nur für die Ebene TCP überladen, damit Sie Daten auf der Konsole drucken können. Was würde es beinhalten? Sie könnten verrückt werden und alle TCP Details analysieren (dh TCP ist komplex) ...

Welches beinhaltet die:

  • Quellport
  • Zielhafen
  • Sequenznummer
  • Bestätigungsnummer
  • Datenoffset
  • Flaggen
  • Fensterversatz
  • Prüfsumme
  • Dringender Zeiger
  • Optionen (Ich werde nicht mal dorthin gehen)

Aber möchten Sie all diesen Müll erhalten, wenn Sie TCP.ToString () für 100 Pakete aufrufen? Natürlich nicht, es wäre eine Informationsüberflutung. Die einfache und offensichtliche Wahl ist auch die vernünftigste ...

Stellen Sie heraus, was die Leute erwarten würden:

  • Quellport
  • Zielhafen

Ich bevorzuge eine sinnvolle Ausgabe, die für Menschen leicht zu analysieren ist, aber YMMV .

TCP:[destination:000, source:000]

Keine Komplexität, die Ausgabe ist nicht für Maschinen zum Parsen vorgesehen (dh es sei denn, die Leute missbrauchen Ihren Code). Der beabsichtigte Zweck besteht in der menschlichen Lesbarkeit.

Aber was ist mit dem ganzen Rest der saftigen Informationen, über die ich vorher gesprochen habe, ist das nicht auch nützlich? Darauf komme ich aber erstmal ...


ToString () eine der wertvollsten und am wenigsten genutzten Methoden aller Zeiten

Aus zwei Gründen:

  1. Die Leute verstehen nicht, wofür ToString () ist
  2. In der Basisklasse 'Object' fehlt eine weitere, ebenso wichtige Zeichenfolgemethode.

Grund 1 - Missbrauchen Sie nicht die Nützlichkeit von ToString ():

Viele Benutzer verwenden ToString (), um eine einfache Zeichenfolgendarstellung eines Objekts abzurufen. Das C # -Handbuch besagt sogar:

ToString ist die wichtigste Formatierungsmethode in .NET Framework. Es konvertiert ein Objekt in seine Zeichenfolgendarstellung, sodass es für die Anzeige geeignet ist.

Anzeige, keine weitere Bearbeitung. Das heißt nicht, dass Sie meine Nice-Zeichenfolgendarstellung des Pakets TCP oben nehmen und den Quellport mit einem regex :: cringe :: abrufen.

Die richtige Methode besteht darin, ToString () direkt in der SourcePort-Eigenschaft aufzurufen (wobei BTW eine Ushort-Funktion ist, sodass ToString () bereits verfügbar sein sollte).

Wenn Sie etwas Robusteres benötigen, um den Status eines komplexen Objekts für die Maschinenanalyse zu packen, sollten Sie eine strukturierte Serialisierungsstrategie verwenden.

Glücklicherweise sind solche Strategien sehr verbreitet:

  • ISerializable (C #)
  • Essiggurke (Python)
  • JSON (Javascript oder eine andere Sprache, die es implementiert)
  • SOAP
  • usw...

Hinweis: Es sei denn, Sie verwenden PHP, da es, Herp-Derp, eine Funktion für that :: snicker :: gibt.

Grund 2 - ToString () ist nicht genug:

Ich habe noch keine Sprache gesehen, die dies im Kern implementiert, aber ich habe Variationen dieses Ansatzes in freier Wildbahn gesehen und verwendet.

Einige davon sind:

  • ToVerboseString ()
  • ToString (verbose = true)

Grundsätzlich sollte das haarige Durcheinander eines TCP-Pakets aus Gründen der menschlichen Lesbarkeit beschrieben werden. Um zu vermeiden, dass ein totes Pferd geschlagen wird, wenn es um TCP geht, zeige ich mit dem Finger auf den ersten Fall, in dem ToString () und ToVerboseString () meiner Meinung nach nicht ausgelastet sind ...

se Case - Arrays:

Wenn Sie hauptsächlich eine Sprache verwenden, sind Sie wahrscheinlich mit dem Ansatz dieser Sprache vertraut. Für Leute wie mich, die zwischen verschiedenen Sprachen wechseln, kann die Anzahl der unterschiedlichen Ansätze irritierend sein.

Dh die Häufigkeit, mit der mich das gereizt hat, ist größer als die Summe aller Finger eines jeden Hindugottes zusammen.

Es gibt verschiedene Fälle, in denen Sprachen häufig Hacks und wenige verwenden, get it right =. Einige müssen neu erfunden werden, andere machen einen flachen Dump, andere machen einen tiefen Dump, keiner von ihnen arbeitet so, wie ich es gerne hätte ...

Ich bitte um einen sehr einfachen Ansatz:

print(array.ToString());

Ausgänge: 'Array [x]' oder 'Array [x] [y]'

Dabei ist x die Anzahl der Elemente in der ersten Dimension und y die Anzahl der Elemente in der zweiten Dimension oder ein Wert, der angibt, dass die zweite Dimension gezackt ist (min/max-Bereich möglicherweise?).

Und:

print(array.ToVerboseString());

Gibt den ganzen She-Bang in hübschem Druck aus, weil ich hübsche Dinge schätze.

Hoffentlich wirft dies ein Licht auf ein Thema, das mich schon lange geärgert hat. Zumindest habe ich ein wenig Troll-Köder für die PHP-Benutzer gesprenkelt, um diese Antwort abzustimmen.

13
Evan Plaice

Eigentlich geht es um gute Praxis.

ToString() wird an vielen Stellen verwendet, um eine Zeichenfolgendarstellung eines Objekts zurückzugeben, im Allgemeinen für den Verbrauch durch einen Menschen. Oft kann die gleiche Zeichenfolge verwendet werden, um das Objekt erneut zu hydratisieren (denken Sie beispielsweise an int oder DateTime), aber das ist nicht immer gegeben (z. B. kann eine Baumstruktur eine nützliche Zeichenfolgendarstellung enthalten, in der einfach eine Anzahl angezeigt wird. benutze das, um es wieder aufzubauen).

Insbesondere verwendet der Debugger diese Option, um die Variable in den Überwachungsfenstern, den unmittelbaren Fenstern usw. anzuzeigen. Daher ist ToString für das Debugging von unschätzbarem Wert.

Im Allgemeinen hat ein solcher Typ auch häufig einen expliziten Member, der auch eine Zeichenfolge zurückgibt. Beispielsweise kann ein Lat/Long-Paar ToDecimalDegrees haben, das beispielsweise "-10, 50" zurückgibt, es kann jedoch auch ToDegreesMinutesSeconds vorhanden sein, da dies ein anderes Format für ein Lat/Long-Paar ist. Derselbe Typ könnte dann auch ToString mit einer dieser Optionen überschreiben, um einen 'Standardwert' für Dinge wie das Debuggen oder sogar für Dinge wie das Rendern von Webseiten bereitzustellen (z. B. schreibt das @-Konstrukt in Razor das ToString()-Ergebnis einer Nichtzeichenfolge Ausdruck an den Ausgabestrom).

9
Andras Zoltan

Obwohl ich denke, dass die nützlichsten Informationen bereits bereitgestellt wurden, werde ich meine zwei Cents hinzufügen:

  • ToString() soll überschrieben werden. Seine Standardimplementierung gibt den Typnamen zurück, der zwar manchmal nützlich ist (insbesondere bei der Arbeit mit vielen Objekten), jedoch in der Mehrzahl der Fälle nicht ausreicht.

  • Beachten Sie, dass Sie sich zu Debugging-Zwecken auf DebuggerDisplayAttribute verlassen können. Sie können mehr darüber lesen hier

  • In der Regel können Sie bei POCOs ToString() immer überschreiben. POCOs sind eine strukturierte Darstellung von Daten, die normalerweise zu einem String werden können.

  • Entwerfen Sie ToString als Textdarstellung Ihres Objekts. Vielleicht die wichtigsten Felder und Daten, vielleicht eine Beschreibung, wie viele Elemente sich in der Sammlung befinden usw.

  • Versuchen Sie immer, diese Zeichenfolge in eine einzige Zeile einzufügen und haben nur wichtige Informationen. Wenn Sie über eine Person-Klasse mit den Eigenschaften Name, Adresse, Nummer usw. verfügen, geben Sie nur die Hauptdaten (Name einige ID-Nummer) zurück. 

  • Achten Sie darauf, eine gute Implementierung von ToString() nicht zu überschreiben. Einige Framework-Klassen implementieren bereits ToString(). Das Überschreiben dieser Standardimplementierung ist eine schlechte Sache: Die Benutzer erwarten ein bestimmtes Ergebnis von ToString() und erhalten ein anderes Ergebnis. 

Haben Sie keine Angst davor, ToString() zu verwenden. Das einzige, was ich vorsichtig sein würde, ist, sensible Informationen zurückzugeben. Abgesehen davon ist das Risiko minimal. Sicherlich, wie einige bereits gesagt haben, verwenden andere Klassen Ihren ToString, wenn Sie nach Informationen suchen. Aber verdammt, wann wird es besser sein, den Typnamen zurückzugeben, als tatsächliche Informationen zu erhalten?

6
Bruno Brant

object.ToString() konvertiert ein Objekt in seine Zeichenfolgendarstellung. Wenn Sie ändern möchten, was zurückgegeben wird, wenn ein Benutzer ToString() für eine von Ihnen erstellte Klasse aufruft, müssen Sie ToString() in dieser Klasse überschreiben.

6
Robbie

Wenn Sie ToString nicht überschreiben, erhalten Sie die Implementierung der Basisklassen. Dies ist für Object nur der Kurzname der Klasse.

Wenn Sie eine andere, sinnvollere oder nützlichere Implementierung von ToString wünschen, überschreiben Sie sie.


Dies kann nützlich sein, wenn Sie eine Liste Ihres Typs als Datenquelle für ein ListBox verwenden, da das ToString automatisch angezeigt wird.

Eine andere Situation tritt auf, wenn Sie Ihren Typ an String.Format übergeben möchten, wodurch ToString aufgerufen wird, um eine Darstellung Ihres Typs zu erhalten.

5
Jodrell

Was noch niemand erwähnt hat: Wenn Sie ToString() überschreiben, können Sie auch ToString(string Formatter) überschreiben, um Folgendes zu tun:

 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;
}

Welches kann nützlich sein.

4

Ein Vorteil des Überschreibens von ToString () ist die Werkzeugunterstützung von Resharper: Alt + Ins -> "Mitglieder formatieren" und schreibt ToString () für Sie.

3

In einigen Fällen ist es einfacher, Werte von benutzerdefinierten Klassen im Debugger-Überwachungsfenster zu lesen. Wenn ich genau weiß, was ich im Überwachungsfenster sehen möchte, wenn ich ToString mit diesen Informationen überschreibe, dann sehe ich es.

2
philologon

Bei der Definition von Strukturen (effektiv Benutzerprimitiven) halte ich es für sinnvoll, übereinstimmende ToString- und Parse- und TryParse-Methoden zu haben, insbesondere für die XML-Serialisierung. In diesem Fall konvertieren Sie den gesamten Status in einen String, damit er später gelesen werden kann.

Klassen sind jedoch mehr zusammengesetzte Strukturen, die normalerweise zu komplex für die Verwendung von ToString und Parse sind. Ihre ToString-Methoden können, anstatt den gesamten Status zu speichern, eine einfache Beschreibung sein, mit deren Hilfe Sie ihren Status ermitteln können, beispielsweise eine eindeutige Kennung wie Name oder ID oder möglicherweise eine Menge für eine Liste.

Wie Robbie gesagt hat, können Sie durch Überschreiben von ToStringToString für eine Referenz als Basis als Typ object aufrufen.

1
Dave Cousineau

Die Object.ToString-Methode sollte nur für Debugging-Zwecke verwendet werden. Die Standardimplementierung zeigt den Objekttypnamen, was nicht sehr nützlich ist. Erwägen Sie, diese Methode zu überschreiben, um bessere Informationen für die Diagnose und das Debugging bereitzustellen. Bitte beachten Sie, dass für Protokollierungsinfrastrukturen häufig auch die ToString-Methode verwendet wird, sodass Sie diese Textfragmente in Ihren Protokolldateien finden.

Nicht gibt lokalisierte Textressourcen innerhalb der Object.ToString-Methode zurück. Der Grund ist, dass die ToString-Methode immer etwas zurückgeben sollte, was der Entwickler verstehen kann. Der Entwickler spricht möglicherweise nicht alle Sprachen, die von der Anwendung unterstützt werden.

Implementieren Sie die IFormattable-Schnittstelle, wenn Sie einen benutzerfreundlichen lokalisierten Text zurückgeben möchten. Diese Schnittstelle definiert eine ToString-Überladung mit den Parametern format und formatProvider. Der formatProvider hilft Ihnen, den Text kulturbewusst zu formatieren.

Siehe auch: Object.ToString und IFormattable

1
jbe

Sie können dies verwenden, wenn Sie ein Objekt mit einer nicht intuitiven Bedeutung der Zeichenfolgendarstellung haben, z. B. Person. Wenn Sie beispielsweise diese Person ausdrucken möchten, können Sie diese Überschreibung verwenden, um das Format vorzubereiten.

1
NickF

Ich bin mit den Rahmenrichtlinien, auf die in anderen Antworten verwiesen wird, zufrieden. Ich möchte jedoch die Anzeige und das Debuggen hervorheben.

Achten Sie darauf, wie Sie ToString in Ihrem Code verwenden. Ihr Code sollte sich nicht auf die Zeichenfolgendarstellung eines Objekts stützen. In diesem Fall sollten Sie unbedingt die entsprechenden Parse Methoden angeben.

Da ToString überall verwendet werden kann, kann es ein Problem für die Wartbarkeit sein, wenn Sie die Zeichenfolgendarstellung eines Objekts zu einem späteren Zeitpunkt ändern möchten. In diesem Fall können Sie nicht nur die Aufrufhierarchie untersuchen, um zu untersuchen, ob Code beschädigt wird.

0
tm1

Einfacher hängt davon ab, wie Ihre Immobilie genutzt wird. Wenn Sie den String nur einmal formatieren müssen, ist es nicht sinnvoll, ihn zu überschreiben.

Es scheint jedoch, dass Sie die ToString-Methode überschreiben, um nicht die normalen Zeichenfolgendaten für Ihre Eigenschaft zurückzugeben, sondern um ein Standardformatierungsmuster auszuführen. Da benutzt du string.format mit padding.

Da Sie sagten, Sie lernten, scheint die Übung auch auf die Kernprinzipien der objektorientierten Programmierung in Bezug auf Kapselung und Wiederverwendung von Code einzugehen.

Das Zeichenfolgeformat, das die Argumente verwendet, die Sie für das Auffüllen festgelegt haben, stellt sicher, dass die Eigenschaft für jeden Code, der sie aufruft, jedes Mal auf dieselbe Weise formatiert wird. In Zukunft müssen Sie nur noch an einem Ort und nicht an vielen Stellen wechseln.

Tolle Frage und auch ein paar tolle Antworten!

0

Ich finde es nützlich, die ToString-Methode für Entitätsklassen zu überschreiben, da hierdurch Probleme schnell erkannt werden können, insbesondere wenn eine Assertion fehlschlägt.

In Übereinstimmung mit dem zuvor Gesagten ist es jedoch eine vom Menschen lesbare Darstellung des fraglichen Objekts.

0
ranjez