Es scheint drei Möglichkeiten zu geben, öffentlich zugängliche Konstanten in C # zu implementieren. Ich bin gespannt, ob es gute Gründe gibt, sich für einen zu entscheiden oder ob es nur eine Frage der persönlichen Präferenz ist.
Auswahl 1 - privates Feld plus Eigenschaftengetter
%Vor%Auswahl 2 - nur Eigenschaftsgetter
%Vor%Auswahl 3 - Nur öffentliches Feld
%Vor%Was empfehlen Sie und warum?
Aktualisieren
Offensichtlich hat sich dies in eine Diskussion darüber verwandelt, ob const
oder static readonly
verwendet werden soll. Nicht genau, was ich beabsichtigte, aber es hat mich gelehrt, dass Wahl 3 definitiv eine schlechte Idee ist, denn wenn der Wert von const in einer zukünftigen Version geändert wird, müssen alle referenzierenden Assemblies neu kompiliert werden.
Allerdings glaube ich nicht, dass irgendjemand Choice 2 schon wirklich diskutiert hat. Ich bin immer noch neugierig, ob es einen Nachteil hat, nur einen Getter zu haben, der einen Wert zurückgibt und sonst nichts.
Die Optionen 1 und 2 sind wirklich gleichwertig.
Es scheint mir, dass es wirklich drei verschiedene Situationen gibt:
Sie wissen sicher, dass sich die Saite nie ändern wird. In diesem Fall ist es sinnvoll, const
zu setzen. (Zum Beispiel ist Math.PI
const. Das wird sich in absehbarer Zeit nicht ändern.) Es gibt einige subtile Auswirkungen auf den Speicher, wenn Sie static readonly
verwenden, aber sie sind sehr unwahrscheinlich. Sie sollten dies nicht tun, wenn der Wert sich ändern könnte und Sie wollen nicht alle Anrufer in dieser Situation neu kompilieren, aus den anderen Gründen. Beachten Sie, dass es für viele Projekte (insbesondere interne Firmen) wirklich kein Problem ist, alle Anrufer neu zu kompilieren.
Sie denken, dass sich die Zeichenkette in Zukunft ändern könnte, aber Sie wissen, dass sie in jeder Version immer eine Konstante sein wird. In diesem Fall ist ein public static readonly
-Feld in Ordnung. Denken Sie daran, dass dies mit Strings, die unveränderlich sind, in Ordnung ist, aber Sie sollten dies nicht mit anderen veränderbaren Typen wie Arrays tun. (Legen Sie entweder unveränderbare Sammlungen frei oder verwenden Sie eine Eigenschaft und geben Sie jedes Mal eine neue Kopie zurück.)
Sie denken, dass sich der String ändern könnte und sich sogar innerhalb der Lebensdauer eines Programms ändern könnte ... zum Beispiel "das aktuelle Datum, formatiert". Verwenden Sie in diesem Fall eine öffentliche statische schreibgeschützte -Eigenschaft (eine mit nur einem Getter). Beachten Sie, dass die Änderung von einem schreibgeschützten Feld zu einer schreibgeschützten Eigenschaft eine Quelle -kompatible Änderung ist, aber keine binäre kompatible Änderung - wenn Sie sich also für meine Sekunde entschieden haben bullet aber dann müssen Sie in die dritte ändern, müssen Sie alles neu kompilieren.
Betrachten Sie
%Vor% Grund: Wenn Sie const
verfügbar machen (und dann anderweitig verbrauchen), wird const
in die Metadaten des konsumierenden Typs eingebettet.
A public static readonly
ist nicht, und da es static readonly
ist, kostet es nur einmal Instanziierung, und es ist unveränderlich wie ein const
.
Der richtige ist die Wahl # 4:
%Vor%Es ist wichtig, ein readonly-Feld anstelle eines öffentlichen const zu verwenden. Der Literalwert von const wird in die IL kompiliert. Wenn Sie den const-Wert ändern und eine Assembly neu kompilieren, die sie verwendet, haben Sie jetzt eine Diskrepanz zu anderen Assemblys, die ebenfalls const verwenden. Diese anderen Assemblys werden weiterhin mit dem alten const-Wert ausgeführt. Sehr schwer zu diagnostizieren.
Dies kann nicht mit einem schreibgeschützten Feld geschehen, die anderen Assemblies lesen immer den aktualisierten Wert. Wenn Sie const verwenden, stellen Sie sicher, dass sie immer privat sind.
Wenn ich abstimmen könnte, würde ich die Antwort von Jon Skeet ablehnen. Um es hinzuzufügen, sind Ihre # 1 und # 2 genau identisch, wie hier in IL gezeigt:
%Vor%Option # 2:
%Vor%Schauen wir uns jetzt Option # 3 an. Nummer 3 unterscheidet sich sehr von # 1 und # 2. Der Grund dafür ist, wie bereits erwähnt, dass # 3 statisch ist, da const statisch ist. Nun wäre die wirkliche Frage, Äpfel mit Äpfeln zu vergleichen, was wäre, wenn # 1 und # 2 statische Accessoren wären? Dann wären sie eher mit # 3 vergleichbar. Derzeit müssten Sie eine Klasse für Option 1 und 2 initialisieren, aber nicht für # 3. Daher gibt es in diesem Fall eine unnötige Initialisierung eines Objekts, und Sie möchten, wann immer möglich, immer statisch verwenden, um genau das zu vermeiden.
Sehen wir uns jetzt Nummer 3 in der IL an:
%Vor%Um Effizienz zu erreichen, würde ich # 3 verwenden. Das wurde mir auch von vielen talentierten Kollegen über die Jahre beigebracht.
Nun, um den weißen Elefanten im Raum anzusprechen. Readonly und const unterscheiden sich dadurch, dass cont zur Kompilierungszeit auftritt und readonly zur Laufzeit auftritt. Statisches readonly wird einmal initialisiert, während nonstatic readonly einmal pro Instanz initialisiert wird. Wenn Sie zum Beispiel Ihre Frage stellen, um eine Klasse von Konstantenzeichenfolgen für Fehlermeldungen zu erstellen, die sich niemals ändern, dann verwenden Sie Option 3 und nicht nur statisch oder sonst wie. Wenn Sie versuchen, Hunderte von Fehlermeldungen zur Laufzeit statt zur Kompilierungszeit zu initialisieren, werden Sie bemerkenswerte Leistungsunterschiede feststellen. Auch, da Sie klar sagen, dass es sich um einen "String handelt, der sich niemals ändert", sollte readonly in diesem Fall nicht einmal berücksichtigt werden, denn "... wird sich niemals ändern". Const und ReadOnly haben ihre Plätze, aber readonly ist nicht für Gegenstände, die sich nie ändern und sind zur Kompilierzeit bekannt.
Eine Eigenschaft scheint wirklich die bessere Wahl zu sein, da das zurückgegebene string
dann nicht in die Metadaten eingebettet ist. const
sind wirklich für den internen Gebrauch bestimmt (als Beispiel könnte eine Versionsnummer in ein const
umgewandelt werden und könnte sich ändern) oder für Werte, die sich absolut niemals ändern werden, soweit der Code darauf verweist.