Kapselung bedeutet, dass der Status eines Objekts nur über eine definierte Schnittstelle erfolgt. Aus diesem Grund kann die Klasse sicherstellen, dass dieser Status immer gültig ist und dem Zweck der Klasse entspricht.
In einigen Fällen entspricht es daher vollkommen dem Prinzip der Kapselung, ein Feld nur öffentlich zugänglich zu machen. Alle möglichen Werte für das Feld gelten für alle anderen möglichen Werte aller anderen Felder, und daher kann der Programmierer aktiv entscheiden, das Feld zuzulassen durch externen Code frei manipuliert werden.
Diese Fälle sind jedoch meist auf Klassen beschränkt, bei denen es sich meist um "einfache alte Daten" handelt. Sie sind auch in dieser Hinsicht nicht sehr interessant, also genug über sie.
In anderen Fällen, in anderen Sprachen, hätte man eine Getter- und Setter-Methode, so etwas wie int getId()einen Wert zu erhalten undvoid setId(int val) zu aktualisieren.
Mit den Eigenschaften können wir dieselbe Syntax zum Lesen und Schreiben mithilfe solcher Methoden verwenden, die wir zum Lesen und Schreiben eines Felds verwenden würden. Dies ist ein guter syntaktischer Zucker, wenn auch nicht lebenswichtig.
(Eigentlich aufgrund der Art und Weise, wie Reflexion funktioniert und Fälle wie DataBinder.Eval es praktisch sein kann, eine Eigenschaft zu haben, selbst wenn ein Feld gut funktionieren würde, aber das ist eine andere Sache).
Bis zur Einführung privater Setter (was sich mit C # 2 tatsächlich geändert hat, ist die Syntax, einen privaten Setter und einen öffentlichen oder geschützten Getter im selben Block zu haben), könnten wir eine private Methode haben, um die Arbeit des privaten Setters zu erledigen Private Setter sind nicht wirklich notwendig. Sie sind zwar praktisch, aber nur syntaktischer Zucker, aber ziemlich nützlich.
Bei der Kapselung geht es nicht darum, ob Ihre Setter (oder Getter) öffentlich, privat, geschützt oder intern sind, sondern darum, ob sie angemessen sind . Beginnen Sie mit der Standardeinstellung, dass jedes Feld privat ist (und dies auch readonly), und fügen Sie bei Bedarf Mitglieder (ob Eigenschaften oder Methoden) hinzu, die diese Felder ändern, und stellen Sie sicher, dass das Objekt bei Änderungen gültig bleibt . Dies stellt sicher, dass die Invariante einer Klasse beibehalten wird, was bedeutet, dass die Regeln, die den gültigen Satz von Zuständen beschreiben, in denen sie sich befinden kann, niemals verletzt werden (Konstruktoren helfen auch, indem sie sicherstellen, dass sie in einem solchen gültigen Zustand beginnen).
Unveränderlich zu sein bedeutet für Ihre letzte Frage, dass eine Klasse keine öffentlichen, geschützten oder internen Setter und keine öffentlichen, geschützten oder internen Methoden hat, die Felder ändern. Es gibt Grade davon, in C # sind drei Grade möglich:
Alle Instanzfelder einer Klasse sind readonly, daher kann auch privater Code sie nicht ändern. Es ist garantiert unveränderlich (alles, was versucht, es zu ändern, wird nicht kompiliert), und möglicherweise können Optimierungen auf dieser Rückseite vorgenommen werden.
Eine Klasse ist von außen unveränderlich, weil kein öffentliches Mitglied etwas ändert, aber nicht garantiert wird, dass readonlyes nicht von innen geändert wird.
Eine Klasse ist von außen gesehen unveränderlich, obwohl sich ein Zustand als Implementierungsdetail ändert. Zum Beispiel könnte ein Feld gespeichert werden, und während von außen versucht wird, es nur den gleichen Wert abzurufen, berechnet der erste derartige Versuch es tatsächlich und speichert es dann zum Abrufen bei nachfolgenden Versuchen.
private File settingsFile = null;und dann in einem der Konstruktoren :if (settingsFile == null) { settingsFile = GetSettingsFile() };. Solche Refactoring-Codes haben mich manchmal zum Weinen gebracht :). Nur weil Sie ein Mitglied vor dem Konstruktor festlegen können, bedeutet dies nicht, dass Sie dies tun sollten, da es bei mehreren Konstruktoren SCHWER ist, der Logik zu folgen. Private Setter zwingen Sie, Werte innerhalb des Konstruktors oder höher festzulegen.