2017-02-22 2 views
3

Es scheint wie eine gute Design-Entscheidung, dass die System.Object Klasse und damit alle Klassen in .NET eine ToString()-Methode zur Verfügung stellen, die, nicht überraschend, eine String-Darstellung des Objekts zurückgibt. Zusätzlich ist diese Methode in C# für native Typen implementiert, so dass sie sich gut in das Typsystem integrieren lassen.Warum gibt es keine inverse zu object.ToString()?

Dies ist oft nützlich, wenn Benutzerinteraktion erforderlich ist. Zum Beispiel können Objekte direkt in GUI-Widgets wie Listen gehalten werden und werden "automatisch" als Text angezeigt.

Was ist das Grundprinzip im Sprachdesign, um keine ähnlich allgemeine object.FromString(string) Methode zur Verfügung zu stellen?

Andere Fragen und ihre Antworten diskutieren mögliche Einwände, aber ich finde sie nicht überzeugend.

  • konnte der Parse ausfallen, während eine Umwandlung in String immer möglich ist.

    • Nun, das nicht hält Parse() Methoden aus bestehenden, nicht wahr? Wenn die Ausnahmebehandlung als unerwünschtes Design betrachtet wird, könnte man immer noch eine TryParse() Methode definieren, deren Standardimplementierung für System.Object einfach false zurückgibt, die aber für konkrete Typen überschrieben wird, wo es sinnvoll ist (z. B. die Typen, bei denen diese Methode heute ohnehin existiert).

    • Alternativ auf einem Minimum würde es schön sein, eine IParseable Schnittstelle zu haben, die ein oder ParseMe()TryParse() Verfahren erklärt, nach dem Vorbild der ICloneable.

  • Kommentar von Tim Schmelter des "Roll your own": Das funktioniert natürlich. Aber ich kann nicht allgemeinen Code für native Typen schreiben oder, sagen wir, IPAddress, wenn ich die Werte analysieren muss; Stattdessen muss ich auf Introspektion zurückgreifen oder Wrapper schreiben, die eine selbstdefinierte Schnittstelle implementieren, die entweder wartungsunfreundlich oder langwierig und fehleranfällig ist.

  • Kommentar von Damien: Eine Schnittstelle kann nur nicht statische Funktionen aus Gründen begründen, die von Eric Lippert here diskutiert werden. Dies ist ein sehr stichhaltiger Einwand. Eine statische Methode TryParse() kann in einer Schnittstelle nicht angegeben werden. Eine virtuelle ParseMe(string) Methode benötigt jedoch ein Dummy-Objekt, das bestenfalls ein Kludge ist und im schlimmsten Fall unmöglich ist (mit RAII). Ich vermute fast, dass dies der Hauptgrund dafür ist, dass eine solche Schnittstelle nicht existiert. Stattdessen gibt es das ausgeklügelte Typumwandlungs-Framework, eine der Alternativen, die als Lösungen für das "statische Interface" -Oxymoron erwähnt wurden.

Aber auch die Einwände aufgeführt gegeben, da das Fehlen einer allgemeinen Parsing-Anlage in das Typsystem oder Sprache erscheint mir als eine peinliche Asymmetrie, dass eine allgemeine ToString() Methode existiert und äußerst nützlich ist.

Wurde das jemals während des Sprach/CLR-Designs diskutiert?

+1

Damit "IParsable" funktioniert, müssen Sie zuerst eine Instanz anfordern. Wenn das Problem darin besteht, "diese Zeichenkette in eine Instanz von X zu verwandeln", ist es etwas peinlich, dass Sie zuerst eine andere Instanz von X erhalten müssen, damit Sie 'FromString()' darauf aufrufen können. –

+0

Was genau wäre das Standardverhalten dafür, nur eine Ausnahme werfen? – juharr

+1

Sie können nur wenige Typen von String in 'OtherType' konvertieren, aber Sie können jeden Typ in' String' konvertieren. Was bringt das? Sie können immer eine Konstruktor- oder Factory-Methode angeben (z. B. mit 'TryParse'-Muster), die eine Instanz aus einer Zeichenfolge erzeugt, wenn dies gewünscht und möglich ist. –

Antwort

10

Warum gibt es keine Umkehrung zu object.ToString()?

Da object sollte die Nötigste Funktionalität von jedes Objekt erforderlich halten. Vergleichen von Gleichheit und Konvertieren in String (aus vielen Gründen) sind zwei von ihnen. Konvertieren ist nicht. Das Problem ist: Wie soll es konvertieren? JSON verwenden? Binär? XML? Etwas anderes? Es gibt keine einheitliche Möglichkeit, eine Zeichenfolge zu konvertieren. Daher würde dies unnötig die Klasse object aufblähen.

Alternativ hierzu kann auf ein Minimum wäre es schön sein, eine IParseable Schnittstelle

Es ist zu haben: IXmlSerializable zum Beispiel, oder eine der vielen Alternativen.

+2

IConvertible ["konvertiert (s) den Wert des implementierenden Verweises oder Werttyps ** in einen Common Language Runtime-Typ." **] (https://msdn.microsoft.com/de-de/library/system.iconvertible (v = vs.110) .aspx) Das ist der umgekehrte Anwendungsfall von mir: mein * Quelltyp * ist ein CLR-Laufzeittyp, nämlich 'string'; Mein * Zieltyp * ist dagegen ein benutzerdefinierter Typ oder eigentlich IPAddress. Alle Typen, die ich parsen möchte, um eine Parse-Methode verfügbar zu machen, aber die Sprache hat nicht die Mittel, diese Gemeinsamkeit auszudrücken. –

+0

Sie haben Recht. Wird das entfernen. –

13

Es scheint wie eine gute Design-Entscheidung, die die System.Object-Klasse und damit alle Klassen, in .NET

Vielleicht Sie eine Methode ToString() zur Verfügung stellen. Es schien mir immer eine wirklich schlechte Idee zu sein.

, die, wenig überraschend, eine String-Darstellung des Objekts zurückgibt.

Geht es aber? Bei den meisten Typen gibt ToString den Namen des Typs zurück. Wie ist das eine String-Darstellung des Objekts?

Nein, ToString war in erster Linie ein schlechtes Design. Es hat keinen klaren Vertrag. Es gibt keine klare Anleitung, was seine Semantik sein sollte, abgesehen davon, keine Nebenwirkungen zu haben und eine Zeichenkette zu produzieren.

Da ToString keinen eindeutigen Vertrag hat, gibt es praktisch nichts, was Sie sicher verwenden können, außer für Debugger-Ausgabe. Ich meine wirklich, darüber nachdenken: Wann haben Sie das letzte Mal ToStringauf Objekt in Produktion Code aufgerufen? Ich habe nie.

Das bessere Design wären daher die Methoden static string ToString<T>(T) und static string ToString(object) auf der Debug Klasse. Diese hätten dann "null" erzeugen können, wenn das Objekt null ist, oder eine Reflexion über T durchgeführt, um festzustellen, ob es einen Debugger-Visualizer für dieses Objekt gibt, und so weiter.

Betrachten wir nun die Vorzüge Ihres tatsächlichen Vorschlags, bei dem es sich um eine allgemeine Anforderung handelt, dass alle Objekte aus der Zeichenfolge deserialisierbar sind. Beachten Sie, dass dies zunächst nicht die umgekehrte Operation von ToString ist. Die überwiegende Mehrheit der ToString-Implementierungen erzeugt nichts, was Sie theoretisch sogar verwenden könnten, um das Objekt zu rekonstruieren.

Also ist Ihr Vorschlag, dass ToString und FromString Inversen sein? Das erfordert dann, dass jedes Objekt nicht nur als String "dargestellt" wird, sondern dass es tatsächlich round trip serializable zu string ist.

Lassen Sie uns an ein Beispiel denken. Ich habe ein Objekt, das eine Datenbanktabelle darstellt. Sorgt ToString für diese Tabelle jetzt für den gesamten Inhalt der Tabelle? FromString deserialisiert es? Angenommen, das Objekt ist tatsächlich ein Wrapper um eine Verbindung, die die Tabelle bei Bedarf abruft; Was serialisieren und deserialisieren wir dann?Wenn die Verbindung mein Passwort benötigt, setzt es mein Passwort in die Zeichenfolge?

Angenommen, ich habe ein Objekt, das auf ein anderes Objekt verweist, so dass ich das erste Objekt nicht deserialisieren kann, ohne auch die zweite in der Hand zu haben. Ist die Serialisierung über Objekte hinweg rekursiv? Was ist mit Objekten, bei denen der Graph der Referenzen Schleifen enthält? Wie gehen wir damit um?

Serialisierung ist schwierig, und deshalb gibt es ganze Bibliotheken, die sich damit beschäftigen. Eine Anforderung zu machen, dass alle Typen serialisierbar und deserialisierbar sein müssen, ist lästig.

Selbst angenommen, dass wir das wollten, warum string aller Dinge? Zeichenfolgen sind ein schrecklicher Serialisierungsdatentyp. Sie können nicht einfach binäre Daten halten, sie müssen vollständig im Speicher auf einmal vorhanden sein, sie können nicht mehr als eine Milliarde Zeichen Tops sein, sie haben keine Struktur für sie und so weiter. Was Sie wirklich für die Serialisierung wollen, ist ein strukturiertes binäres Speichersystem.

Aber auch die Einwände aufgeführt gegeben, wird das Fehlen einer allgemeinen Parsing Einrichtung in der Art System oder die Sprache zu mir als eine peinliche Asymmetrie gegeben, dass eine allgemeine Methode ToString() existiert und äußerst nützlich ist.

Das sind zwei völlig verschiedene Dinge, die nichts miteinander zu tun haben. Eines ist ein sehr hartes Problem, das am besten von Bibliotheken gelöst wird, die sich damit beschäftigen, und das andere ist eine triviale kleine Debug-Hilfe, bei der keine Spezifikation die Ausgabe einschränkt.

Wurde das jemals während des Sprach/CLR-Designs diskutiert?

Wurde ToString jemals diskutiert? Offensichtlich war es; es wurde umgesetzt. Wurde jemals eine verallgemeinerte Serialisierungsbibliothek diskutiert? Offensichtlich war es; es wurde umgesetzt. Ich bin mir nicht sicher, worauf Sie hier hinauswollen.

+0

Danke für die ausführliche Antwort. (1) Re "' ToString() 'hauptsächlich nützlich für das Debugging": Ich verlasse mich auch darauf in meinen GUIs (z. B. Objekte in Listen, Datagrids). (2) Ihre Einwände bezüglich Round-Trip-Semantik/-Serialisierung: Punkt genommen. Aber ich habe das nicht für den allgemeinen Fall vorgeschlagen. (Das heißt, object.Parse() schlägt immer fehl.) Es gibt jedoch ein Spektrum von Typen - z. alle nativen Typen - die eine round-trip Textdarstellung haben. Und wie bei 'ICloneable', gegen das auch Einwände bezüglich des Nicht-Vertrags gemacht wurden: Es liegt am Benutzer, es mit der gewünschten Semantik zu definieren. –

Verwandte Themen