Die wahre Definition der Unveränderlichkeit?

8

Ich frage mich, wie Unveränderlichkeit definiert ist? Wenn die Werte nicht öffentlich angezeigt werden, also nicht geändert werden können, reicht das?

Können die Werte innerhalb des Typs geändert werden, nicht vom Kunden des Typs?

Oder kann man sie nur in einem Konstruktor setzen? Wenn ja, ist es in den Fällen der doppelten Initialisierung (mit dem this Schlüsselwort auf Strukturen usw.) immer noch in Ordnung für unveränderliche Typen?

Wie kann ich garantieren, dass der Typ 100% unveränderlich ist?

    
Joan Venge 26.05.2009, 21:28
quelle

10 Antworten

23
  

Wenn die Werte nicht öffentlich angezeigt werden, also nicht geändert werden können, reicht das?

Nein, weil Sie Lesezugriff benötigen.

  

Können die Werte innerhalb des Typs geändert werden, nicht vom Kunden des Typs?

Nein, weil das immer noch Mutation ist.

  

Oder kann man sie nur in einem Konstruktor setzen?

Ding ding! Mit dem zusätzlichen Punkt, dass unveränderliche Typen oft Methoden haben, die neue Instanzen konstruieren und zurückgeben, und haben oft zusätzliche Konstruktoren, die speziell für diese Methoden mit internal markiert sind.

  

Wie kann ich garantieren, dass der Typ 100% unveränderlich ist?

In .Net ist es schwierig, eine Garantie wie diese zu bekommen, weil Sie mit reflection private Mitglieder modifizieren (mutieren) können.

    
Joel Coehoorn 26.05.2009, 21:31
quelle
7

Die vorherigen Poster haben bereits erklärt, dass Sie Ihren Feldern im Konstruktor Werte zuweisen sollten und dann die Finger davon lassen sollten. Aber das ist manchmal leichter gesagt als getan. Angenommen, Ihr unveränderliches Objekt macht eine Eigenschaft vom Typ List<string> verfügbar. Darf diese Liste geändert werden? Und wenn nicht, wie kontrollieren Sie es?

Eric Lippert hat in seinem Blog eine Reihe von Posts über Unveränderlichkeit in C # geschrieben, die Sie vielleicht interessant finden: finden Sie den ersten Teil hier .

    
Fredrik Mörk 26.05.2009 21:36
quelle
5

Eine Sache, die ich bei all diesen Antworten vielleicht übersehen habe, ist, dass ich ein Objekt als unveränderlich betrachten kann, selbst wenn sich sein interner Zustand ändert - solange diese internen Änderungen für den "Client" -Code nicht sichtbar sind.

Zum Beispiel ist die System.String -Klasse unveränderlich, aber ich denke, es wäre erlaubt, den Hash-Code für eine Instanz zu cachen, so dass der Hash nur beim ersten Aufruf von GetHashCode() berechnet wird. Beachten Sie, dass, soweit ich weiß, die System.String -Klasse dies nicht tut, aber ich denke, dass sie als unveränderlich betrachtet werden kann und immer noch betrachtet werden kann. Natürlich müsste jede dieser Änderungen in einer Thread-sicheren Weise gehandhabt werden (in Übereinstimmung mit dem nicht beobachtbaren Aspekt der Änderungen).

Um ehrlich zu sein, kann ich mir nicht viele Gründe vorstellen, warum man diese Art von "unsichtbarer Veränderlichkeit" möchte oder braucht.

    
Michael Burr 27.05.2009 00:35
quelle
3

Hier ist die Definition der Unveränderlichkeit von Wikipedia ( link )

"In der objektorientierten und funktionalen Programmierung ist ein unveränderliches Objekt ein Objekt, dessen Zustand nach der Erstellung nicht geändert werden kann."

Nachdem das Objekt erstellt wurde, kann im Wesentlichen keine seiner Eigenschaften geändert werden. Ein Beispiel ist die String-Klasse. Sobald ein String-Objekt erstellt wurde, kann es nicht mehr geändert werden. Jede Operation, die damit ausgeführt wird, erzeugt tatsächlich ein neues String-Objekt.

    
Mr. Will 26.05.2009 21:32
quelle
3

Viele Fragen dort. Ich werde versuchen, sie alle einzeln zu beantworten:

  • "Ich frage mich, wie Unveränderlichkeit definiert ist?" - Direkt von der Wikipedia-Seite (und einer sehr genauen / prägnanten Definition)

      

    Ein unveränderliches Objekt ist ein Objekt, dessen Status nach der Erstellung nicht geändert werden kann.

  • "Wenn die Werte nicht öffentlich angezeigt werden, also nicht geändert werden können, reicht das?" - Nicht ganz. Es kann nicht in irgendwie geändert werden , so dass Sie sicherstellen müssen, dass Methoden / Funktionen den Zustand des Objekts nicht ändern, und wenn Sie Operationen ausführen, immer eine neue Instanz zurückgeben.

  • "Können die Werte innerhalb des Typs geändert werden, nicht vom Kunden des Typs?" - Technisch kann es nicht innerhalb oder durch einen Verbraucher des Typs geändert werden. In der Praxis existieren Typen wie System.String (ein Referenztyp für die Materie), die für fast alle praktischen Zwecke als veränderbar angesehen werden können, wenn auch nicht in der Theorie.

  • "Oder kann man sie nur in einem Konstruktor setzen?" - Ja, in der Theorie ist dies der einzige Ort, an dem der Status (Variablen) eingestellt werden kann.

  • "Wenn ja, ist es in den Fällen der doppelten Initialisierung (mit dem Schlüsselwort this auf Strukturen usw.) immer noch in Ordnung für unveränderliche Typen?" - Ja, das ist immer noch völlig in Ordnung, weil es alles Teil des Initialisierungs (Erstellungs) prozesses ist und die Instanz erst zurückgegeben wird, wenn sie beendet ist.

  • "Wie kann ich garantieren, dass der Typ 100% unveränderlich ist?" - Die folgenden Bedingungen sollten dies gewährleisten. (Jemand bitte darauf hinweisen, wenn ich einen vermisse.)

    1. Setzen Sie keine Variablen frei. Sie sollten alle private behalten (nicht einmal protected ist akzeptabel, da abgeleitete Klassen dann den Status ändern können).
    2. Lassen Sie keine Instanzmethoden den Status (Variablen) ändern. Dies sollte nur im Konstruktor erfolgen, während Methoden neue Instanzen mit einem bestimmten Konstruktor erstellen sollten, wenn sie ein "modifiziertes" Objekt zurückgeben müssen.
    3. Alle Member, die (als schreibgeschützt) verfügbar gemacht werden oder Objekte, die von Methoden zurückgegeben werden, müssen selbst unveränderlich sein.

    Hinweis: Sie können die Unveränderlichkeit abgeleiteter Typen nicht sicherstellen, da sie neue Variablen definieren können. Dies ist ein Grund dafür, einen beliebigen Typ zu markieren, um sicherzustellen, dass er als sealed unveränderlich ist, so dass keine abgeleitete Klasse irgendwo im Code als unveränderlicher Basis-Typ betrachtet werden kann.

Ich hoffe, das hilft.

    
Noldorin 26.05.2009 21:36
quelle
1

Ich habe gelernt, dass Unveränderbarkeit ist, wenn Sie alles im Konstruktor festlegen und später während der Lebensdauer des Objekts nicht ändern können.

    
Eric 26.05.2009 21:32
quelle
1

Die Definition der Unveränderlichkeit kann auf Google gefunden werden.

Beispiel:

  

unveränderlich - buchstäblich, nicht in der Lage zu ändern.
  www.filosofia.net/materiales/rec/glosaen.htm

Im Hinblick auf unveränderbare Datenstrukturen lautet die typische Definition "einmal schreiben, mehrere lesen". Anders ausgedrückt: Wenn Sie das einmal erstellt haben, kann es nicht mehr geändert werden.

Es gibt einige Fälle, die leicht in der Grauzone liegen. Beispielsweise werden .NET-Zeichenfolgen als unveränderlich betrachtet, da sie nicht geändert werden können. StringBuilder ändert jedoch intern ein Zeichenfolgenobjekt.

    
quelle
1

Ein Unveränderliches ist im Wesentlichen eine Klasse, die sich dazu zwingt, aus ihrem eigenen Code endgültig zu sein. Sobald es da ist, kann nichts geändert werden. In meinem Wissen werden Dinge im Konstruktor festgelegt und das ist es dann. Ich sehe nicht, wie etwas anders unveränderlich sein könnte.

    
Nathan Lawrence 26.05.2009 21:34
quelle
1

Es gibt leider keine unveränderlichen Schlüsselwörter in c # / vb.net, obwohl es diskutiert wurde, aber wenn es keine autoproperties gibt und alle Felder mit readonly deklariert sind (schreibgeschützte Felder können nur im Konstruktor zugewiesen werden) modfier und alle Felder Wird von einem unveränderlichen Typ erklärt, haben Sie Ihre eigene Unveränderlichkeit versichert.

    
Rune FS 27.05.2009 06:06
quelle
1

Ein unveränderliches Objekt ist eines, dessen beobachtbarer Zustand niemals durch irgendeine plausible Sequenz der Codeausführung geändert werden kann. Ein unveränderlicher Typ ist einer, der garantiert, dass alle Instanzen, die der Außenwelt ausgesetzt sind, unveränderlich sein werden (diese Anforderung wird oft als Bedingung angegeben, dass der Zustand des Objekts nur in seinem Konstruktor gesetzt werden darf; dies ist bei Objekten mit private Konstruktoren, noch ist es ausreichend bei Objekten, die während der Konstruktion externe Methoden auf sich selbst anwenden.)

Ein Punkt, den andere Antworten vernachlässigt haben, ist jedoch eine Definition des Zustands eines Objekts. Wenn Foo eine Klasse ist, besteht der Zustand von List<Foo> aus der Folge von Objektidentitäten , die darin enthalten sind. Wenn der einzige Verweis auf eine bestimmte List<Foo> -Instanz von Code gehalten wird, der weder dazu führt, dass diese Sequenz geändert wird, noch ihn einem Code aussetzt, der dies tun könnte, wird diese Instanz unabhängig davon, ob die Foo -Objekte sind, unveränderlich sein darauf bezogen sind veränderbar oder unveränderlich.

Um eine Analogie zu verwenden: Wenn eine Liste von Fahrzeug-VINs (Vehicle Identification Numbers) auf manipulationssicherem Papier gedruckt ist, wäre die Liste selbst unveränderlich, obwohl es Autos nicht sind. Selbst wenn die Liste heute zehn rote Autos enthält, könnte sie morgen zehn blaue Autos enthalten; sie würden jedoch immer noch dieselben zehn Autos sein .

    
supercat 14.08.2012 22:59
quelle

Tags und Links