Ich muss eine schreibgeschützte Eigenschaft für meinen Typ implementieren . Darüber hinaus wird der Wert dieser Eigenschaft im Konstruktor festgelegt und nicht geändert (ich schreibe eine Klasse, die benutzerdefinierte geroutete UI-Befehle für WPF verfügbar macht, aber das spielt keine Rolle).
Ich sehe zwei Möglichkeiten, dies zu tun:
class MyClass { public readonly object MyProperty = new object(); }
class MyClass { private readonly object my_property = new object(); public object MyProperty { get { return my_property; } } }
Mit all diesen FxCop-Fehlern, die besagen, dass ich keine öffentlichen Mitgliedsvariablen haben sollte, scheint es, dass die zweite der richtige Weg ist, dies zu tun. Richtig?
Gibt es in diesem Fall einen Unterschied zwischen einer get only-Eigenschaft und einem schreibgeschützten Mitglied?
Ich würde mich über Kommentare / Ratschläge / etc.
c#
properties
readonly
akonsu
quelle
quelle
get; readonly set;
Option enthält.get; private set;
.{get;}
kurzem Unterstützung hinzugefügt , wodurch dieses Problem behoben wird .Antworten:
Versionierung:
Ich denke, es macht keinen großen Unterschied, wenn Sie nur an der Quellkompatibilität interessiert sind.
Die Verwendung einer Eigenschaft ist aus Gründen der Binärkompatibilität besser, da Sie sie durch eine Eigenschaft mit einem Setter ersetzen können, ohne den kompilierten Code abhängig von Ihrer Bibliothek zu beschädigen.
Konvention:
Sie folgen der Konvention. In solchen Fällen, in denen die Unterschiede zwischen den beiden Möglichkeiten nach der Konvention relativ gering sind, ist dies besser. Ein Fall, in dem es zurückkommen könnte, um Sie zu beißen, ist reflexionsbasierter Code. Möglicherweise werden nur Eigenschaften und keine Felder akzeptiert, z. B. ein Eigenschafteneditor / -betrachter.
Serialisierung
Wenn Sie von Feld zu Eigenschaft wechseln, werden wahrscheinlich viele Serialisierer beschädigt. Und AFAIK
XmlSerializer
serialisiert nur öffentliche Objekte und keine öffentlichen Felder.Verwenden einer Autoproperty
Eine weitere häufige Variante ist die Verwendung einer Autoproperty mit einem privaten Setter. Dies ist zwar kurz und eine Eigenschaft, erzwingt jedoch nicht die Lesbarkeit. Also bevorzuge ich die anderen.
Das schreibgeschützte Feld ist selbstdokumentierend. Das Feld hat
jedoch einen Vorteil:
Auf einen Blick auf die öffentliche Schnittstelle wird deutlich, dass es tatsächlich unveränderlich ist (außer bei Reflexion). Während Sie bei einer Eigenschaft nur sehen können, dass Sie sie nicht ändern können, müssen Sie sich auf die Dokumentation oder Implementierung beziehen.
Aber um ehrlich zu sein, verwende ich den ersten ziemlich oft im Anwendungscode, da ich faul bin. In Bibliotheken bin ich normalerweise gründlicher und folge der Konvention.
C # 6.0 fügt schreibgeschützte automatische Eigenschaften hinzu
public object MyProperty { get; }
Wenn Sie also keine älteren Compiler unterstützen müssen, können Sie eine wirklich schreibgeschützte Eigenschaft mit Code haben, der genauso präzise ist wie ein schreibgeschütztes Feld.
quelle
public type prop => get;
Der zweite Weg ist die bevorzugte Option.
private readonly int MyVal = 5; public int MyProp { get { return MyVal;} }
Dadurch wird sichergestellt, dass
MyVal
dies nur bei der Initialisierung zugewiesen werden kann (es kann auch in einem Konstruktor festgelegt werden).Wie Sie bereits bemerkt haben, stellen Sie auf diese Weise kein internes Mitglied zur Verfügung, sodass Sie die interne Implementierung in Zukunft ändern können.
quelle
public int MyProp { get; private set; }
? Ich weiß, dass es nicht wirklich schreibgeschützt ist, aber es ist verdammt nah dran.Mit der Einführung von C # 6 (in VS 2015) können Sie jetzt nur
get
noch automatische Eigenschaften haben, in denen sich das implizite Sicherungsfeld befindetreadonly
(dh Werte können im Konstruktor zugewiesen werden, aber nicht anderswo):public string Name { get; } public Customer(string name) // Constructor { Name = name; } private void SomeFunction() { Name = "Something Else"; // Compile-time error }
Und Sie können jetzt auch Eigenschaften (mit oder ohne Setter) inline initialisieren:
public string Name { get; } = "Boris";
Wenn Sie auf die Frage zurückkommen, erhalten Sie die Vorteile von Option 2 (öffentliches Mitglied ist eine Eigenschaft, kein Feld) mit der Kürze von Option 1.
Leider bietet es keine Garantie für Unveränderlichkeit auf der Ebene der öffentlichen Schnittstelle (wie in @ CodesInChaos 'Punkt zur Selbstdokumentation), da für einen Verbraucher der Klasse kein Setter von einem privaten Setter nicht zu unterscheiden ist.
quelle
readonly
Felder durch Reflexion geändert werden können (ich kenne die Antwort nicht, aber es scheint problematisch)?Du kannst das:
public int Property { get { ... } private set { ... } }
quelle
Ich stimme zu, dass der zweite Weg vorzuziehen ist. Der einzige wirkliche Grund für diese Einstellung ist die allgemeine Einstellung, dass .NET-Klassen keine öffentlichen Felder haben. Wenn dieses Feld jedoch schreibgeschützt ist, kann ich nicht erkennen, wie es zu echten Einwänden kommen würde, außer einer mangelnden Konsistenz mit anderen Eigenschaften. Der wirkliche Unterschied zwischen einem schreibgeschützten Feld und einer Nur-Erhalten-Eigenschaft besteht darin, dass das Nur-Lesen-Feld eine Garantie dafür bietet, dass sich sein Wert während der Lebensdauer des Objekts nicht ändert und eine Nur-Erhalten-Eigenschaft nicht.
quelle
Das zweite Verfahren ist wegen der Einkapselung bevorzugt. Sie können sicher sein, dass das schreibgeschützte Feld öffentlich ist, aber das widerspricht C # -Sprachen, bei denen der Datenzugriff über Eigenschaften und nicht über Felder erfolgt.
Der Grund dafür ist, dass die Eigenschaft eine öffentliche Schnittstelle definiert. Wenn sich die Backing-Implementierung dieser Eigenschaft ändert, wird der Rest des Codes nicht beschädigt, da die Implementierung hinter einer Schnittstelle verborgen ist.
quelle
noch ein anderer Weg (mein Favorit), beginnend mit C # 6
private readonly int MyVal = 5; public int MyProp => MyVal;
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties#expression-body-definitions
quelle
public int MyProp { get; } = 5;
?In C # 9 wird Microsoft eine neue Methode einführen, mit der Eigenschaften nur bei der Initialisierung mithilfe der folgenden
init;
Methode festgelegt werden:public class Person { public string firstName { get; init; } public string lastName { get; init; } }
Auf diese Weise können Sie beim Initialisieren eines neuen Objekts Werte zuweisen:
var person = new Person { firstname = "John", lastName = "Doe" }
Aber später können Sie es nicht ändern:
person.lastName = "Denver"; // throws a compiler error
quelle