Die allgemeine Anleitung für C # besteht darin, eine Eigenschaft immer über einem öffentlichen Feld zu verwenden. Dies ist sinnvoll. Wenn Sie ein Feld verfügbar machen, werden viele Implementierungsdetails verfügbar gemacht. Mit einer Eigenschaft kapseln Sie dieses Detail so, dass es keinen Code verbraucht und Implementierungsänderungen von Schnittstellenänderungen entkoppelt werden.
Ich frage mich jedoch, ob es beim Umgang mit dem readonly
Schlüsselwort manchmal eine gültige Ausnahme von dieser Regel gibt . Indem Sie dieses Schlüsselwort auf ein öffentliches Feld anwenden, geben Sie eine zusätzliche Garantie: Unveränderlichkeit. Dies ist nicht nur ein Implementierungsdetail, Unveränderlichkeit ist etwas, an dem ein Verbraucher interessiert sein könnte. Die Verwendung eines readonly
Felds macht es Teil des öffentlichen Auftrags und etwas, das nicht durch zukünftige Änderungen oder Vererbung gebrochen werden kann, ohne auch die öffentliche Schnittstelle ändern zu müssen. Das kann eine Immobilie nicht bieten.
Ist die Gewährleistung der Unveränderlichkeit readonly
in einigen Fällen ein legitimer Grund, ein Feld einer Immobilie vorzuziehen?
(Zur Verdeutlichung sage ich sicherlich nicht, dass Sie diese Wahl immer treffen sollten , nur weil das Feld im Moment unveränderlich ist, nur wenn es als Teil des Klassendesigns sinnvoll ist und beabsichtigt ist, Unveränderlichkeit in den Vertrag aufzunehmen. Ich interessiere mich hauptsächlich für Antworten, die sich darauf konzentrieren, ob dies gerechtfertigt ist, und nicht für bestimmte Fälle, in denen dies nicht der Fall ist, z. B. wenn das Mitglied auf einem Mitglied sein interface
muss oder wenn Sie faul laden möchten.)
quelle
Antworten:
Öffentliche statische schreibgeschützte Felder sind sicherlich in Ordnung. Sie werden für bestimmte Situationen empfohlen, z. B. wenn Sie ein benanntes, konstantes Objekt möchten, das
const
Schlüsselwort jedoch nicht verwenden können .Schreibgeschützte Mitgliederfelder sind etwas kniffliger. Es gibt nicht viel Vorteil gegenüber einer Immobilie ohne einen öffentlichen Setter, und es gibt einen großen Nachteil: Felder können nicht Mitglieder von Schnittstellen sein. Wenn Sie sich also dazu entschließen, Ihren Code so umzugestalten, dass er für eine Schnittstelle anstelle eines konkreten Typs verwendet wird, müssen Sie Ihre schreibgeschützten Felder in Eigenschaften mit öffentlichen Gettern ändern.
Eine öffentliche nicht virtuelle Eigenschaft ohne geschützten Setter bietet Schutz vor Vererbung, es sei denn, die geerbten Klassen haben Zugriff auf das Sicherungsfeld. Sie können diesen Vertrag in der Basisklasse vollständig durchsetzen.
In diesem Fall ist es kein großes Hindernis, die "Unveränderlichkeit" des Mitglieds nicht ändern zu können, ohne die öffentliche Schnittstelle der Klasse zu ändern. Wenn Sie ein öffentliches Feld in eine Eigenschaft ändern möchten, funktioniert dies normalerweise reibungslos, mit der Ausnahme, dass Sie sich mit zwei Fällen befassen müssen:
object.Location.X = 4
ist nur möglich, wennLocation
es sich um ein Feld handelt. Dies ist jedoch für ein schreibgeschütztes Feld nicht relevant, da Sie eine schreibgeschützte Struktur nicht ändern können. (Dies setzt voraus, dassLocation
es sich um einen Werttyp handelt. Wenn nicht, würde dieses Problem ohnehin nicht auftreten, dareadonly
es nicht vor solchen Dingen schützt.)out
oder übergibtref
. Auch dies ist nicht wirklich relevant für einen Nur - Lese - Bereich, daout
undref
Parameter zu erhalten geändert neigen, und es ist ein Compiler - Fehler ohnehin einen Nur - Lese - Wert oder ref passieren.Mit anderen Worten, obwohl das Konvertieren eines schreibgeschützten Felds in eine schreibgeschützte Eigenschaft die Binärkompatibilität beeinträchtigt, müsste anderer Quellcode nur ohne Änderungen neu kompiliert werden, um diese Änderung zu verarbeiten. Das macht die Garantie wirklich leicht zu brechen.
Ich sehe keine Vorteile für das
readonly
Mitgliederfeld, und die Unfähigkeit, so etwas auf einer Schnittstelle zu haben, ist für mich ein Nachteil genug, dass ich es nicht verwenden würde.quelle
Nach meiner Erfahrung ist das
readonly
Schlüsselwort nicht die Magie, die es verspricht.Sie haben beispielsweise eine Klasse, in der der Konstruktor früher einfach war. Angesichts der Verwendung (und der Tatsache, dass einige der Klasseneigenschaften / -felder nach der Erstellung unveränderlich sind) könnten Sie denken, dass dies keine Rolle spielt, also haben Sie das
readonly
Schlüsselwort verwendet.Später wird die Klasse komplexer, ebenso wie ihr Konstruktor. (Nehmen wir an, dies geschieht in einem Projekt, das entweder experimentell ist oder eine ausreichend hohe Geschwindigkeit hat, die außerhalb des Bereichs / der Kontrolle zoomt, aber Sie müssen dafür sorgen, dass es irgendwie funktioniert.) Sie werden feststellen, dass Felder, die
readonly
nur innerhalb des Konstruktors geändert werden können - Sie kann es in Methoden nicht ändern, selbst wenn diese Methode nur von einem Konstruktor aufgerufen wird.Diese technische Einschränkung wurde von den Designern von C # anerkannt und wird möglicherweise in einer zukünftigen Version behoben. Aber bis es behoben ist, ist die Verwendung von
readonly
restriktiver und kann zu einem schlechten Codierungsstil führen (alles in die Konstruktormethode einfügen).Zur Erinnerung: Weder eine
readonly
noch nicht öffentlich festgelegte Eigenschaft bietet eine Garantie für ein "vollständig initialisiertes Objekt". Mit anderen Worten, es ist der Designer einer Klasse, der entscheidet, was "vollständig initialisiert" bedeutet und wie er vor versehentlichem Gebrauch geschützt werden soll. Ein solcher Schutz ist im Allgemeinen nicht narrensicher, was bedeutet, dass jemand einen Weg finden könnte, ihn zu umgehen.quelle
readonly
Feld alsout
oderref
Parameter an andere Methoden übergeben, die es dann nach Belieben ändern können.Felder sind IMMER Implementierungsdetails. Sie möchten Ihre Implementierungsdetails nicht offenlegen.
Ein grundlegender Grundsatz des Software-Engineerings ist, dass wir nicht wissen, welche Anforderungen in Zukunft gestellt werden. Auch
readonly
wenn Ihr Fachgebiet heute gut ist, gibt es keine Anhaltspunkte dafür, dass es Teil der Anforderungen von morgen sein wird. Was ist, wenn morgen ein Trefferzähler implementiert werden muss, um zu bestimmen, wie oft auf dieses Feld zugegriffen wird? Was ist, wenn Sie zulassen müssen, dass Unterklassen das Feld überschreiben?Eigenschaften sind so einfach zu verwenden und so viel flexibler als öffentliche Felder, dass ich mir keinen einzigen Anwendungsfall vorstellen kann, in dem ich sowohl c # als meine Sprache auswählen als auch öffentliche schreibgeschützte Felder für eine Klasse verwenden würde. Wenn die Leistung so gering wäre, dass ich den zusätzlichen Methodenaufruf nicht ertragen könnte, würde ich wahrscheinlich eine andere Sprache verwenden.
Nur weil wir können etwas mit der Sprache tun, bedeutet nicht , wir sollten etwas mit der Sprache tun.
Ich frage mich tatsächlich, ob die Sprachdesigner es bereuen, Felder veröffentlicht zu haben. Ich kann mich nicht erinnern, wann ich das letzte Mal in Betracht gezogen habe, nicht konstante öffentliche Felder in meinem Code zu verwenden.
quelle
Rational
mit öffentlichen, unveränderlichenNumerator
undDenominator
Mitgliedern, kann ich sehr sicher sein, dass diese Mitglieder kein Lazy-Loading oder einen Trefferzähler benötigen oder ähnlich?float
Typen für dieNumerator
undDenominator
nicht müssen geändert werdendoubles
?float
noch seindouble
. Sie sollten seinint
,long
oderBigInteger
. Vielleicht müssen sich diese ändern ... aber wenn ja, müssten sie sich auch in der öffentlichen Oberfläche ändern. Wenn Sie also wirklich Eigenschaften verwenden, wird dieses Detail nicht gekapselt.Nein, das ist keine Rechtfertigung.
Das Readonly als Garantie für Unveränderlichkeit und nicht als Rechtfertigung zu verwenden, ist eher ein Hack.
Readonly bedeutet, dass der Wert von einem Konstruktor o zugewiesen wird, wenn die Variable definiert wird.
Ich denke, es wird eine schlechte Praxis sein
Wenn Sie wirklich Unveränderlichkeit garantieren möchten, verwenden Sie eine Schnittstelle, die mehr Vor- als Nachteile hat.
Einfaches Schnittstellenbeispiel:
quelle