Ich habe eine Klasse mit zwei readonly int
Feldern. Sie sind als Eigenschaften ausgesetzt:
public class Thing
{
private readonly int _foo, _bar;
/// <summary> I AM IMMUTABLE. </summary>
public Thing(int foo, int bar)
{
_foo = foo;
_bar = bar;
}
public int Foo { get { return _foo; } set { } }
public int Bar { get { return _bar; } set { } }
}
Dies bedeutet jedoch, dass das Folgende vollkommen legal ist:
Thing iThoughtThisWasMutable = new Thing(1, 42);
iThoughtThisWasMutable.Foo = 99; // <-- Poor, mistaken developer.
// He surely has bugs now. :-(
Die Fehler, die von der Annahme ausgehen, dass dies funktionieren würde, werden mit Sicherheit heimtückisch sein. Sicher, der falsche Entwickler sollte die Dokumentation gelesen haben. Das ändert aber nichts an der Tatsache, dass ihn kein Kompilierungs- oder Laufzeitfehler vor dem Problem gewarnt hat.
Wie sollte die Thing
Klasse geändert werden, damit Entwickler mit geringerer Wahrscheinlichkeit den oben genannten Fehler machen?
Eine Ausnahme auslösen? Verwenden Sie eine Get-Methode anstelle einer Eigenschaft?
c#
object-oriented
immutability
properties
kdbanman
quelle
quelle
Interfaces
. Ich bin nicht sicher, ob ich das tue.Antworten:
Warum diesen Code legal machen?
Nehmen Sie das raus,
set { }
wenn es nichts tut.So definieren Sie eine schreibgeschützte öffentliche Eigenschaft:
quelle
public int Foo { get; }
(Auto-Property mit nur einem Getter), aberpublic int Foo { get; private set; }
ist.In C # 5 und früheren Versionen standen uns zwei Optionen für unveränderliche Felder gegenüber, die über einen Getter verfügbar gemacht wurden:
readonly
, um die Unveränderlichkeit zu zerstören. Es wurde jedoch viel Code für die Kesselplatte erstellt.Mit C # 6 (verfügbar in VS2015, das gestern veröffentlicht wurde) erhalten wir jetzt das Beste aus beiden Welten: schreibgeschützte automatische Eigenschaften. Dies ermöglicht es uns, die Klasse des OP zu vereinfachen, um:
Die Zeilen
Foo = foo
undBar = bar
sind nur im Konstruktor gültig (der die robuste Nur-Lese-Anforderung erfüllt) und das Hintergrundfeld ist impliziert, anstatt explizit definiert zu werden (was den einfacheren Code ermöglicht).quelle
Man könnte die Setter einfach loswerden. Sie tun nichts, sie werden die Benutzer verwirren und zu Fehlern führen. Sie können sie jedoch stattdessen als privat kennzeichnen und so die Sicherungsvariablen entfernen, was Ihren Code vereinfacht:
quelle
public int Foo { get; private set; }
Diese Klasse ist nicht länger unveränderlich, weil sie sich selbst ändern kann." Trotzdem danke!readonly
Schlüsselwort ist nur ein Poka-Joch, dh es schützt vor der Klasse, die in Zukunft die Unveränderlichkeit bricht. es wird jedoch nicht benötigt, um Unveränderlichkeit zu erreichen.Zwei Lösungen.
Einfach:
Schließen Sie keine Setter ein, wie von David für unveränderliche schreibgeschützte Objekte angegeben.
Alternative:
Setter können ein neues unveränderliches Objekt zurückgeben, das im Vergleich zum vorherigen ausführlich ist, jedoch für jedes initialisierte Objekt den Status über die Zeit angibt. Dieses Design ist ein sehr nützliches Werkzeug für die Thread-Sicherheit und Unveränderlichkeit, das sich über alle wichtigen OOP-Sprachen erstreckt.
Pseudocode
öffentliche statische Fabrik
quelle