@donstack, tatsächlich nach der C # Referenz , kann ein Nur - Lese - Feld zugewiesen werden , und sie mehrmals innerhalb der Felddeklarations und Konstruktor neu zugewiesen.
Marques
Antworten:
1289
Abgesehen von dem offensichtlichen Unterschied von
Das Deklarieren des Werts zum Zeitpunkt einer Definition für einen constVS- readonlyWert kann dynamisch berechnet werden, muss jedoch zugewiesen werden, bevor der Konstruktor beendet wird. Danach wird er eingefroren.
'const's sind implizit static. Sie verwenden eine ClassName.ConstantNameNotation, um darauf zuzugreifen.
Es gibt einen subtilen Unterschied. Betrachten Sie eine Klasse, die in definiert ist AssemblyA.
AssemblyBverweist AssemblyAund verwendet diese Werte im Code. Wenn dies kompiliert ist,
im Falle des constWertes ist es wie ein Suchen-Ersetzen, der Wert 2 wird in die AssemblyBIL des 'eingebrannt' . Dies bedeutet, dass ich morgen I_CONST_VALUEauf 20 aktualisieren werde . AssemblyBhätte noch 2 bis ich es neu kompiliere .
im Falle des readonlyWertes ist es wie refein Speicherort. Der Wert wird nicht in AssemblyBdie IL eingebrannt . Dies bedeutet, dass bei einer Aktualisierung des Speicherorts AssemblyBder neue Wert ohne Neukompilierung abgerufen wird . Wenn I_RO_VALUEalso auf 30 aktualisiert wird, müssen Sie nur erstellen AssemblyA. Alle Clients müssen nicht neu kompiliert werden.
Wenn Sie also sicher sind, dass sich der Wert der Konstante nicht ändert, verwenden Sie a const.
publicconstint CM_IN_A_METER =100;
Wenn Sie jedoch eine Konstante haben, die sich ändern kann (z. B. Genauigkeit), oder verwenden Sie im Zweifelsfall a readonly.
publicreadonlyfloat PI =3.14;
Update: Aku muss erwähnt werden, weil er zuerst darauf hingewiesen hat. Außerdem muss ich einstecken, wo ich das gelernt habe. Effektives C # - Bill Wagner
Der staticPunkt scheint der wichtigste und nützlichste Punkt zu sein -consts are implicitly static
LCJ
28
Der Teil über Referenzwerte ist der wichtigste. Konstantenwerte können weg optimiert werden.
CodingBarfield
22
readonlyVariablen können außerhalb des Konstruktors geändert werden (Reflektion). Es ist nur der Compiler, der versucht, Sie daran zu hindern, die Variable außerhalb des Konstruktors zu ändern.
Bitterblue
12
@ mini-me- readonlyVariablen dürfen nach Abschluss des Konstruktors auch durch Reflektion nicht mehr geändert werden. Die Laufzeit erzwingt dies nicht. Die Laufzeit kommt auch nicht zu erzwingen , dass Sie sich nicht ändern string.Emptyzu "Hello, world!", aber ich würde behaupten , noch nicht , dass dies macht string.Emptymodifizierbar, oder dass Code sollte nicht davon ausgehen , dass string.Emptyimmer eine leere Zeichenfolge sein.
Es gibt eine Gotcha mit Konstanten! Wenn Sie auf eine Konstante aus einer anderen Assembly verweisen, wird deren Wert direkt in die aufrufende Assembly kompiliert. Auf diese Weise ändert sich die Konstante in der aufgerufenen Assembly nicht, wenn Sie sie in der aufrufenden Assembly aktualisieren!
Bei der Dekompilierung (Reflector, ILSpy, ..) wird NIEMALS auf eine Konstante verwiesen, unabhängig von derselben Assembly oder einer anderen Assembly. Daher können Sie die Verwendung einer Konstante in kompiliertem Code überhaupt nicht analysieren.
springy76
159
Konstanten
Konstanten sind standardmäßig statisch
Sie müssen zur Kompilierungszeit einen Wert haben (Sie können z. B. 3,14 * 2 haben, aber keine Methoden aufrufen).
Könnte innerhalb von Funktionen deklariert werden
Werden in jede Assembly kopiert, die sie verwendet (jede Assembly erhält eine lokale Kopie der Werte)
Kann in Attributen verwendet werden
Schreibgeschützte Instanzfelder
Muss einen festgelegten Wert haben, wenn der Konstruktor beendet wird
Werden beim Erstellen einer Instanz ausgewertet
Statische schreibgeschützte Felder
Werden ausgewertet, wenn die Codeausführung auf die Klassenreferenz trifft (wenn eine neue Instanz erstellt oder eine statische Methode ausgeführt wird)
Muss einen ausgewerteten Wert haben, bis der statische Konstruktor fertig ist
Es wird nicht empfohlen, ThreadStaticAttribute auf diese zu setzen (statische Konstruktoren werden nur in einem Thread ausgeführt und legen den Wert für seinen Thread fest; alle anderen Threads haben diesen Wert nicht initialisiert).
Nur um hinzuzufügen, macht ReadOnly für Referenztypen nur die Referenz schreibgeschützt, nicht die Werte. Zum Beispiel:
publicclassConst_V_Readonly{publicconstint I_CONST_VALUE =2;publicreadonlychar[] I_RO_VALUE =newChar[]{'a','b','c'};publicUpdateReadonly(){
I_RO_VALUE[0]='V';//perfectly legal and will update the value
I_RO_VALUE =newchar[]{'V'};//will cause compiler error}}
Gibt es einen anderen Referenztyp als den string, den Sie als Konstante verwenden könnten?
springy76
Sie können constmit anderen Referenztypen als Zeichenfolge haben, aber die Konstante kann nur den Wert haben null.
Mike Rosoft
40
Das erklärt es . Zusammenfassung: const muss zur Deklarationszeit initialisiert werden, schreibgeschützt kann auf dem Konstruktor initialisiert werden (und hat daher je nach verwendetem Konstruktor einen anderen Wert).
EDIT: Siehe Gishus Gotcha oben für den subtilen Unterschied
Es gibt eine kleine Gotcha mit Readonly. Ein schreibgeschütztes Feld kann innerhalb der Konstruktoren mehrfach festgelegt werden. Auch wenn der Wert in zwei verschiedenen verketteten Konstruktoren festgelegt ist, ist er weiterhin zulässig.
publicclassSample{privatereadonlystring ro;publicSample(){
ro ="set";}publicSample(stringvalue):this(){
ro =value;// this works even though it was set in the no-arg ctor}}
Ein konstantes Mitglied wird zur Kompilierungszeit definiert und kann zur Laufzeit nicht geändert werden. Konstanten werden mit dem constSchlüsselwort als Feld deklariert und müssen beim Deklarieren initialisiert werden.
Ein readonlyMitglied ist insofern wie eine Konstante, als es einen unveränderlichen Wert darstellt. Der Unterschied besteht darin, dass ein readonlyMitglied zur Laufzeit in einem Konstruktor initialisiert werden kann und auch beim Deklarieren initialisiert werden kann.
Sie können nicht statisch sein , sie sind statisch. Sie sollten static const int i = 0;
klarstellen
Können Sie erklären, warum constDeklarationen nicht innerhalb von Methoden abgegeben werden können?
Minh Tran
21
Eine Konstante ist eine Konstante zur Kompilierungszeit, während schreibgeschützt die Berechnung eines Werts zur Laufzeit und die Festlegung im Konstruktor oder Feldinitialisierer ermöglicht. Ein 'const' ist also immer konstant, aber 'readonly' ist schreibgeschützt, sobald es zugewiesen wurde.
Eric Lippert vom C # -Team hat weitere Informationen zu verschiedenen Arten der Unveränderlichkeit
Der Wert Ihrer const-Eigenschaft wird zur Kompilierungszeit festgelegt und kann zur Laufzeit nicht geändert werden
Const kann nicht als statisch markiert werden - das Schlüsselwort gibt an, dass sie statisch sind, im Gegensatz zu schreibgeschützten Feldern, die dies können.
Const kann nichts anderes als Werttypen (primitive Typen) sein
Das schreibgeschützte Schlüsselwort markiert das Feld als unveränderlich. Die Eigenschaft kann jedoch im Konstruktor der Klasse geändert werden
Das schreibgeschützte Schlüsselwort kann auch mit static kombiniert werden, damit es sich wie eine Konstante verhält (zumindest auf der Oberfläche). Es gibt einen deutlichen Unterschied, wenn Sie die IL zwischen den beiden betrachten
const-Felder werden in IL als "Literal" markiert, während readonly "initonly" ist.
Ich glaube, ein constWert ist für alle Objekte gleich (und muss mit einem wörtlichen Ausdruck initialisiert werden), während er readonlyfür jede Instanziierung unterschiedlich sein kann ...
Eines der Teammitglieder in unserem Büro gab die folgenden Anweisungen zur Verwendung von const, static und readonly:
Verwenden Sie const, wenn Sie eine Variable eines Typs haben, von dem Sie zur Laufzeit wissen können (Zeichenfolgenliteral, int, double, enums, ...), dass alle Instanzen oder Konsumenten einer Klasse Zugriff darauf haben sollen, wo sich der Wert nicht ändern soll.
Verwenden Sie statisch, wenn Sie Daten haben, auf die alle Instanzen oder Konsumenten einer Klasse Zugriff haben sollen, auf die sich der Wert ändern kann.
Verwenden Sie statisch schreibgeschützt, wenn Sie eine Variable eines Typs haben, den Sie zur Laufzeit nicht kennen können (Objekte), auf die alle Instanzen oder Konsumenten einer Klasse Zugriff haben sollen, auf die sich der Wert nicht ändern soll.
Verwenden Sie schreibgeschützt, wenn Sie eine Variable auf Instanzebene haben, die Sie zum Zeitpunkt der Objekterstellung kennen und die sich nicht ändern sollte.
Eine letzte Anmerkung: Ein const-Feld ist statisch, aber die Umkehrung ist nicht wahr.
Ich denke du meinst "unterhalten". Die Umkehrung wäre "ein nicht konstantes Feld ist nicht statisch". Welches kann oder kann nicht wahr sein. Die Umkehrung "ein statisches Feld ist (immer) const" ist nicht wahr.
Michael Blackburn
5
Sie sind beide konstant, aber eine Konstante ist auch zur Kompilierungszeit verfügbar. Dies bedeutet, dass ein Aspekt des Unterschieds darin besteht, dass Sie const-Variablen als Eingabe für Attributkonstruktoren verwenden können, jedoch keine schreibgeschützten Variablen.
Beispiel:
publicstaticclassText{publicconststringConstDescription="This can be used.";publicreadonlystaticstringReadonlyDescription="Cannot be used.";}publicclassFoo{[Description(Text.ConstDescription)]publicintBarThatBuilds{{get;set;}}[Description(Text.ReadOnlyDescription)]publicintBarThatDoesNotBuild{{get;set;}}}
Kompilierungszeitkonstante : Absolutkonstante , Wert wird während der Deklaration festgelegt, befindet sich im IL-Code selbst
readonly
Laufzeitkonstante : Kann im Konstruktor / Init über die Konfigurationsdatei festgelegt werden, dh nach der App.configInitialisierung kann sie nicht mehr geändert werden
Mit const gekennzeichnete Variablen sind kaum mehr als stark typisierte # define-Makros. Zur Kompilierungszeit werden const-Variablenreferenzen durch Inline-Literalwerte ersetzt. Infolgedessen können auf diese Weise nur bestimmte integrierte primitive Werttypen verwendet werden. Nur schreibgeschützt markierte Variablen können in einem Konstruktor zur Laufzeit festgelegt werden, und ihre schreibgeschützte Schreibweise wird auch zur Laufzeit erzwungen. Dies ist mit geringfügigen Leistungskosten verbunden, bedeutet jedoch, dass Sie schreibgeschützt für jeden Typ (auch für Referenztypen) verwenden können.
Außerdem sind const-Variablen von Natur aus statisch, während schreibgeschützte Variablen bei Bedarf instanzspezifisch sein können.
Es wurde hinzugefügt, dass consts stark typisierte #define- Makros sind. Andernfalls können wir alle C- oder C ++ - Leute abschrecken. :-)
Jason Baker
4
CONST
Das Schlüsselwort const kann auf Felder oder lokale Variablen angewendet werden
Wir müssen das Feld const zum Zeitpunkt der Deklaration zuweisen
Kein Speicher zugeordnet Da der const-Wert nach der Kompilierung in den IL-Code selbst eingebettet ist. Es ist so, als würde man alle Vorkommen der Variablen const finden und durch ihren Wert ersetzen. Daher hat der IL-Code nach der Kompilierung fest codierte Werte anstelle von const-Variablen
Const in C # sind standardmäßig statisch.
Der Wert ist für alle Objekte konstant
Es gibt ein Problem mit der DLL-Versionierung - Dies bedeutet, dass jedes Mal, wenn wir eine öffentliche const-Variable oder -Eigenschaft ändern (tatsächlich sollte sie theoretisch nicht geändert werden), eine andere DLL oder Assembly, die diese Variable verwendet, neu erstellt werden muss
Nur integrierte C # -Typen können als konstant deklariert werden
Das Const-Feld kann nicht als ref- oder out-Parameter übergeben werden
Schreibgeschützt
Das Schlüsselwort readonly gilt nur für Felder, nicht für lokale Variablen
Wir können schreibgeschützte Felder zum Zeitpunkt der Deklaration oder im Konstruktor zuweisen, nicht in anderen Methoden.
dynamischer Speicher für schreibgeschützte Felder zugewiesen und wir können den Wert zur Laufzeit erhalten.
Readonly gehört zu dem Objekt, das so erstellt wurde, dass nur über eine Instanz der Klasse zugegriffen werden kann. Um es zum Klassenmitglied zu machen, müssen wir statisches Schlüsselwort hinzufügen, bevor wir schreibgeschützt sind.
Der Wert kann je nach verwendetem Konstruktor unterschiedlich sein (da er zum Objekt der Klasse gehört).
Wenn Sie einen nicht-primitiven Typ (Referenztyp) als schreibgeschützt deklarieren, ist nur die Referenz unveränderlich, nicht das darin enthaltene Objekt.
Da der Wert zur Laufzeit abgerufen wird, gibt es kein Problem mit der DLL-Versionierung mit schreibgeschützten Feldern / Eigenschaften.
Wir können schreibgeschütztes Feld als ref- oder out-Parameter im Konstruktorkontext übergeben.
Da const wirklich nur mit grundlegenden Datentypen funktioniert, fühlen Sie sich möglicherweise "gezwungen", ReadOnly zu verwenden, wenn Sie mit einer Klasse arbeiten möchten. Vorsicht vor der Falle! ReadOnly bedeutet, dass Sie das Objekt nicht durch ein anderes Objekt ersetzen können (Sie können es nicht auf ein anderes Objekt verweisen lassen). Jeder Prozess, der auf das Objekt verweist, kann die Werte im Objekt ändern !
Denken Sie also nicht, dass ReadOnly impliziert, dass ein Benutzer nichts ändern kann. In C # gibt es keine einfache Syntax, die verhindert, dass bei einer Instanziierung einer Klasse die internen Werte geändert werden (soweit ich weiß).
Ja, das ist eher ein allgemeines Thema. Wenn Sie eine get only-Eigenschaft haben, die eine Arrayliste verfügbar macht, können Sie die Arrayliste dennoch ändern. Sie können für diese Eigenschaft keine andere Arrayliste festlegen, aber Sie können den Benutzer nicht daran hindern, die Arrayliste zu ändern.
Gishu
3
A constmuss fest codiert sein , wo readonlydies im Konstruktor der Klasse festgelegt werden kann.
Es gibt einen bemerkenswerten Unterschied zwischen const- und schreibgeschützten Feldern in C # .Net
const ist standardmäßig statisch und muss mit einem konstanten Wert initialisiert werden, der später nicht mehr geändert werden kann. Wertänderungen sind auch in Konstruktoren nicht zulässig. Es kann nicht mit allen Datentypen verwendet werden. Zum Beispiel DateTime. Es kann nicht mit dem Datentyp DateTime verwendet werden.
readonly kann als statisch deklariert werden, ist aber nicht erforderlich. Zum Zeitpunkt der Deklaration ist keine Initialisierung erforderlich. Sein Wert kann mit dem Konstruktor zugewiesen oder geändert werden. Es bietet also Vorteile, wenn es als Instanzklassenmitglied verwendet wird. Zwei verschiedene Instanziierungen können unterschiedliche Werte für das schreibgeschützte Feld haben. Zum Beispiel -
class A
{publicreadonlyintId;public A(int i){Id= i;}}
Dann kann das schreibgeschützte Feld wie folgt mit sofortigen spezifischen Werten initialisiert werden:
A objOne =new A(5);
A objTwo =new A(10);
Hier hat die Instanz objOne den Wert des schreibgeschützten Feldes 5 und objTwo den Wert 10. Dies ist mit const nicht möglich.
Eine Konstante wird als Literalwert in den Consumer kompiliert, während die statische Zeichenfolge als Referenz auf den definierten Wert dient.
Versuchen Sie als Übung, eine externe Bibliothek zu erstellen und in einer Konsolenanwendung zu verwenden, ändern Sie dann die Werte in der Bibliothek und kompilieren Sie sie neu (ohne das Consumer-Programm neu zu kompilieren), legen Sie die DLL in dem Verzeichnis ab und führen Sie die EXE-Datei manuell aus dass sich die konstante Zeichenfolge nicht ändert.
@ Andrew Hare - ja, ich habe gerade nachgesehen. Ich bin sehr überrascht, das ist ein echtes Problem, ich bin wirklich sehr überrascht, erstaunt, dass das der Fall ist ...!
ljs
Ich lehne jedoch die Verwendung des Wortzeigers hier ab. Es ist kein Zeiger, es ist eine Referenz, und es gibt einen Unterschied in C #, da Sie nicht verwaltete Zeiger im unsicheren Modus bearbeiten können. Daher ist es wichtig, zwischen beiden zu unterscheiden.
ljs
2
Konstante
Wir müssen den Wert für das const-Feld bereitstellen, wenn es definiert ist. Der Compiler speichert dann den Wert der Konstante in den Metadaten der Assembly. Dies bedeutet, dass eine Konstante nur für den primitiven Typ wie Boolescher Wert, Zeichen, Byte usw. definiert werden kann. Konstanten werden immer als statische Elemente betrachtet, nicht als Instanzmitglieder.
Schreibgeschützt
Schreibgeschützte Felder können nur zur Laufzeit aufgelöst werden. Das heißt, wir können einen Wert für einen Wert mithilfe des Konstruktors für den Typ definieren, in dem das Feld deklariert ist. Die Überprüfung wird vom Compiler durchgeführt, dass schreibgeschützte Felder von keiner anderen Methode als dem Konstruktor beschrieben werden.
Hauptsächlich; Sie können einem statischen schreibgeschützten Feld zur Laufzeit einen Wert für einen nicht konstanten Wert zuweisen, während einer Konstante ein konstanter Wert zugewiesen werden muss.
Const und Readonly sind ähnlich, aber sie sind nicht genau gleich. Ein const-Feld ist eine Konstante zur Kompilierungszeit, was bedeutet, dass dieser Wert zur Kompilierungszeit berechnet werden kann. Ein schreibgeschütztes Feld ermöglicht zusätzliche Szenarien, in denen während der Erstellung des Typs Code ausgeführt werden muss. Nach der Erstellung kann ein schreibgeschütztes Feld nicht mehr geändert werden.
Zum Beispiel können const-Mitglieder verwendet werden, um Mitglieder wie folgt zu definieren:
da Werte wie 3.14 und 0 Konstanten zur Kompilierungszeit sind. Betrachten Sie jedoch den Fall, in dem Sie einen Typ definieren und einige vorgefertigte Instanzen davon bereitstellen möchten. Beispielsweise möchten Sie möglicherweise eine Farbklasse definieren und "Konstanten" für gängige Farben wie Schwarz, Weiß usw. bereitstellen. Dies ist mit const-Elementen nicht möglich, da die rechten Seiten keine Konstanten zur Kompilierungszeit sind. Man könnte dies mit regulären statischen Mitgliedern tun:
publicclassColor{publicstaticColorBlack=newColor(0,0,0);publicstaticColorWhite=newColor(255,255,255);publicstaticColorRed=newColor(255,0,0);publicstaticColorGreen=newColor(0,255,0);publicstaticColorBlue=newColor(0,0,255);privatebyte red, green, blue;publicColor(byte r,byte g,byte b){
red = r;
green = g;
blue = b;}}
Aber dann gibt es nichts, was einen Kunden von Color davon abhält, sich damit zu beschäftigen, vielleicht indem er die Schwarz-Weiß-Werte vertauscht. Dies würde natürlich andere Kunden der Color-Klasse bestürzen. Die Funktion "Nur Lesen" behebt dieses Szenario. Indem wir einfach das schreibgeschützte Schlüsselwort in die Deklarationen einfügen, behalten wir die flexible Initialisierung bei und verhindern gleichzeitig, dass Client-Code herumwirbelt.
publicclassColor{publicstaticreadonlyColorBlack=newColor(0,0,0);publicstaticreadonlyColorWhite=newColor(255,255,255);publicstaticreadonlyColorRed=newColor(255,0,0);publicstaticreadonlyColorGreen=newColor(0,255,0);publicstaticreadonlyColorBlue=newColor(0,0,255);privatebyte red, green, blue;publicColor(byte r,byte g,byte b){
red = r;
green = g;
blue = b;}}
Es ist interessant festzustellen, dass const-Elemente immer statisch sind, während ein schreibgeschütztes Element entweder statisch sein kann oder nicht, genau wie ein reguläres Feld.
Es ist möglich, ein einzelnes Schlüsselwort für diese beiden Zwecke zu verwenden, dies führt jedoch entweder zu Versionsproblemen oder zu Leistungsproblemen. Nehmen wir für einen Moment an, dass wir ein einziges Schlüsselwort für dieses (const) verwendet haben und ein Entwickler schrieb:
publicclass A
{publicstaticconst C =0;}
und ein anderer Entwickler schrieb Code, der sich auf A stützte:
publicclass B
{staticvoidMain(){Console.WriteLine(A.C);}}
Kann der generierte Code nun auf der Tatsache beruhen, dass AC eine Konstante zur Kompilierungszeit ist? Kann die Verwendung von AC einfach durch den Wert 0 ersetzt werden? Wenn Sie dazu "Ja" sagen, bedeutet dies, dass der Entwickler von A die Art und Weise, wie AC initialisiert wird, nicht ändern kann - dies bindet die Hände des Entwicklers von A ohne Erlaubnis. Wenn Sie zu dieser Frage "Nein" sagen, wird eine wichtige Optimierung übersehen. Vielleicht ist der Autor von A sicher, dass AC immer Null sein wird. Die Verwendung von const und readonly ermöglicht es dem Entwickler von A, die Absicht anzugeben. Dies sorgt für ein besseres Versionsverhalten und eine bessere Leistung.
Der Unterschied besteht darin, dass der Wert eines statischen schreibgeschützten Felds zur Laufzeit festgelegt wird, sodass es für verschiedene Programmausführungen einen anderen Wert haben kann. Der Wert eines const-Feldes wird jedoch auf eine Kompilierungszeitkonstante gesetzt.
Denken Sie daran: Bei Referenztypen verhindert der schreibgeschützte Modifikator in beiden Fällen (statisch und instanziell) nur, dass Sie dem Feld eine neue Referenz zuweisen. Insbesondere macht es das Objekt, auf das in der Referenz verwiesen wird, nicht unveränderlich.
Konstante Variablen werden zur Kompilierungszeit deklariert und initialisiert. Der Wert kann nach den Stationen nicht mehr geändert werden. Schreibgeschützte Variablen werden nur vom statischen Konstruktor der Klasse initialisiert. Schreibgeschützt wird nur verwendet, wenn der Wert zur Laufzeit zugewiesen werden soll.
Ihre Definition von "Readonly", die sich ändern kann, ist fehlerhaft. Ich denke mit "ändern" meinten Sie "setzen", wie "es kann zur Laufzeit gesetzt werden".
Ahmed
0
Eine Sache, die man zu dem hinzufügen sollte, was die Leute oben gesagt haben. Wenn Sie eine Assembly haben, die einen schreibgeschützten Wert enthält (z. B. readonly MaxFooCount = 4;), können Sie den Wert ändern, den aufrufende Assemblys sehen, indem Sie eine neue Version dieser Assembly mit einem anderen Wert versenden (z. B. readonly MaxFooCount = 5;).
Aber mit einer Konstante würde es beim Kompilieren des Anrufers in den Code des Anrufers gefaltet.
Wenn Sie dieses Niveau der C # -Kompetenz erreicht haben, sind Sie bereit für Bill Wagners Buch Effective C #: 50 spezifische Möglichkeiten zur Verbesserung Ihres C #, das diese Frage ausführlich beantwortet (und 49 andere Dinge).
Antworten:
Abgesehen von dem offensichtlichen Unterschied von
const
VS-readonly
Wert kann dynamisch berechnet werden, muss jedoch zugewiesen werden, bevor der Konstruktor beendet wird. Danach wird er eingefroren.static
. Sie verwenden eineClassName.ConstantName
Notation, um darauf zuzugreifen.Es gibt einen subtilen Unterschied. Betrachten Sie eine Klasse, die in definiert ist
AssemblyA
.AssemblyB
verweistAssemblyA
und verwendet diese Werte im Code. Wenn dies kompiliert ist,const
Wertes ist es wie ein Suchen-Ersetzen, der Wert 2 wird in dieAssemblyB
IL des 'eingebrannt' . Dies bedeutet, dass ich morgenI_CONST_VALUE
auf 20 aktualisieren werde .AssemblyB
hätte noch 2 bis ich es neu kompiliere .readonly
Wertes ist es wieref
ein Speicherort. Der Wert wird nicht inAssemblyB
die IL eingebrannt . Dies bedeutet, dass bei einer Aktualisierung des SpeicherortsAssemblyB
der neue Wert ohne Neukompilierung abgerufen wird . WennI_RO_VALUE
also auf 30 aktualisiert wird, müssen Sie nur erstellenAssemblyA
. Alle Clients müssen nicht neu kompiliert werden.Wenn Sie also sicher sind, dass sich der Wert der Konstante nicht ändert, verwenden Sie a
const
.Wenn Sie jedoch eine Konstante haben, die sich ändern kann (z. B. Genauigkeit), oder verwenden Sie im Zweifelsfall a
readonly
.Update: Aku muss erwähnt werden, weil er zuerst darauf hingewiesen hat. Außerdem muss ich einstecken, wo ich das gelernt habe. Effektives C # - Bill Wagner
quelle
static
Punkt scheint der wichtigste und nützlichste Punkt zu sein -consts are implicitly static
readonly
Variablen können außerhalb des Konstruktors geändert werden (Reflektion). Es ist nur der Compiler, der versucht, Sie daran zu hindern, die Variable außerhalb des Konstruktors zu ändern.readonly
Variablen dürfen nach Abschluss des Konstruktors auch durch Reflektion nicht mehr geändert werden. Die Laufzeit erzwingt dies nicht. Die Laufzeit kommt auch nicht zu erzwingen , dass Sie sich nicht ändernstring.Empty
zu"Hello, world!"
, aber ich würde behaupten , noch nicht , dass dies machtstring.Empty
modifizierbar, oder dass Code sollte nicht davon ausgehen , dassstring.Empty
immer eine leere Zeichenfolge sein.Es gibt eine Gotcha mit Konstanten! Wenn Sie auf eine Konstante aus einer anderen Assembly verweisen, wird deren Wert direkt in die aufrufende Assembly kompiliert. Auf diese Weise ändert sich die Konstante in der aufgerufenen Assembly nicht, wenn Sie sie in der aufrufenden Assembly aktualisieren!
quelle
Konstanten
Schreibgeschützte Instanzfelder
Statische schreibgeschützte Felder
quelle
Nur um hinzuzufügen, macht ReadOnly für Referenztypen nur die Referenz schreibgeschützt, nicht die Werte. Zum Beispiel:
quelle
string
, den Sie als Konstante verwenden könnten?const
mit anderen Referenztypen als Zeichenfolge haben, aber die Konstante kann nur den Wert habennull
.Das erklärt es . Zusammenfassung: const muss zur Deklarationszeit initialisiert werden, schreibgeschützt kann auf dem Konstruktor initialisiert werden (und hat daher je nach verwendetem Konstruktor einen anderen Wert).
EDIT: Siehe Gishus Gotcha oben für den subtilen Unterschied
quelle
const
: Kann nirgendwo geändert werden.readonly
: Dieser Wert kann nur im Konstruktor geändert werden. Kann in normalen Funktionen nicht geändert werden.quelle
Es gibt eine kleine Gotcha mit Readonly. Ein schreibgeschütztes Feld kann innerhalb der Konstruktoren mehrfach festgelegt werden. Auch wenn der Wert in zwei verschiedenen verketteten Konstruktoren festgelegt ist, ist er weiterhin zulässig.
quelle
Ein konstantes Mitglied wird zur Kompilierungszeit definiert und kann zur Laufzeit nicht geändert werden. Konstanten werden mit dem
const
Schlüsselwort als Feld deklariert und müssen beim Deklarieren initialisiert werden.Ein
readonly
Mitglied ist insofern wie eine Konstante, als es einen unveränderlichen Wert darstellt. Der Unterschied besteht darin, dass einreadonly
Mitglied zur Laufzeit in einem Konstruktor initialisiert werden kann und auch beim Deklarieren initialisiert werden kann.const
static
(sie sind implizit statisch).schreibgeschützt
quelle
static const int i = 0;
const
Deklarationen nicht innerhalb von Methoden abgegeben werden können?Eine Konstante ist eine Konstante zur Kompilierungszeit, während schreibgeschützt die Berechnung eines Werts zur Laufzeit und die Festlegung im Konstruktor oder Feldinitialisierer ermöglicht. Ein 'const' ist also immer konstant, aber 'readonly' ist schreibgeschützt, sobald es zugewiesen wurde.
Eric Lippert vom C # -Team hat weitere Informationen zu verschiedenen Arten der Unveränderlichkeit
quelle
Hier ist ein weiterer Link, der zeigt, dass const nicht versionssicher oder für Referenztypen relevant ist.
Zusammenfassung :
quelle
Nur lesen : Wert geändert durch Ctor zur Laufzeit werden kann. Aber nicht durch die Mitgliedsfunktion
Konstante : Standardmäßig statisch. Der Wert kann von keiner Stelle aus geändert werden (Ctor, Funktion, Laufzeit usw. nirgendwo).
quelle
Noch ein Gotcha: Readonly-Werte können durch "verschlagenen" Code durch Reflexion geändert werden.
Kann ich ein privates schreibgeschütztes geerbtes Feld in C # mithilfe von Reflection ändern?
quelle
Ich glaube, ein
const
Wert ist für alle Objekte gleich (und muss mit einem wörtlichen Ausdruck initialisiert werden), während erreadonly
für jede Instanziierung unterschiedlich sein kann ...quelle
Eines der Teammitglieder in unserem Büro gab die folgenden Anweisungen zur Verwendung von const, static und readonly:
Eine letzte Anmerkung: Ein const-Feld ist statisch, aber die Umkehrung ist nicht wahr.
quelle
Sie sind beide konstant, aber eine Konstante ist auch zur Kompilierungszeit verfügbar. Dies bedeutet, dass ein Aspekt des Unterschieds darin besteht, dass Sie const-Variablen als Eingabe für Attributkonstruktoren verwenden können, jedoch keine schreibgeschützten Variablen.
Beispiel:
quelle
wann zu verwenden
const
oderreadonly
const
readonly
App.config
Initialisierung kann sie nicht mehr geändert werdenquelle
Mit const gekennzeichnete Variablen sind kaum mehr als stark typisierte # define-Makros. Zur Kompilierungszeit werden const-Variablenreferenzen durch Inline-Literalwerte ersetzt. Infolgedessen können auf diese Weise nur bestimmte integrierte primitive Werttypen verwendet werden. Nur schreibgeschützt markierte Variablen können in einem Konstruktor zur Laufzeit festgelegt werden, und ihre schreibgeschützte Schreibweise wird auch zur Laufzeit erzwungen. Dies ist mit geringfügigen Leistungskosten verbunden, bedeutet jedoch, dass Sie schreibgeschützt für jeden Typ (auch für Referenztypen) verwenden können.
Außerdem sind const-Variablen von Natur aus statisch, während schreibgeschützte Variablen bei Bedarf instanzspezifisch sein können.
quelle
CONST
Schreibgeschützt
quelle
Noch ein Gotcha .
Da const wirklich nur mit grundlegenden Datentypen funktioniert, fühlen Sie sich möglicherweise "gezwungen", ReadOnly zu verwenden, wenn Sie mit einer Klasse arbeiten möchten. Vorsicht vor der Falle! ReadOnly bedeutet, dass Sie das Objekt nicht durch ein anderes Objekt ersetzen können (Sie können es nicht auf ein anderes Objekt verweisen lassen). Jeder Prozess, der auf das Objekt verweist, kann die Werte im Objekt ändern !
Denken Sie also nicht, dass ReadOnly impliziert, dass ein Benutzer nichts ändern kann. In C # gibt es keine einfache Syntax, die verhindert, dass bei einer Instanziierung einer Klasse die internen Werte geändert werden (soweit ich weiß).
quelle
A
const
muss fest codiert sein , woreadonly
dies im Konstruktor der Klasse festgelegt werden kann.quelle
Es gibt einen bemerkenswerten Unterschied zwischen const- und schreibgeschützten Feldern in C # .Net
const ist standardmäßig statisch und muss mit einem konstanten Wert initialisiert werden, der später nicht mehr geändert werden kann. Wertänderungen sind auch in Konstruktoren nicht zulässig. Es kann nicht mit allen Datentypen verwendet werden. Zum Beispiel DateTime. Es kann nicht mit dem Datentyp DateTime verwendet werden.
readonly kann als statisch deklariert werden, ist aber nicht erforderlich. Zum Zeitpunkt der Deklaration ist keine Initialisierung erforderlich. Sein Wert kann mit dem Konstruktor zugewiesen oder geändert werden. Es bietet also Vorteile, wenn es als Instanzklassenmitglied verwendet wird. Zwei verschiedene Instanziierungen können unterschiedliche Werte für das schreibgeschützte Feld haben. Zum Beispiel -
Dann kann das schreibgeschützte Feld wie folgt mit sofortigen spezifischen Werten initialisiert werden:
Hier hat die Instanz objOne den Wert des schreibgeschützten Feldes 5 und objTwo den Wert 10. Dies ist mit const nicht möglich.
quelle
Eine Konstante wird als Literalwert in den Consumer kompiliert, während die statische Zeichenfolge als Referenz auf den definierten Wert dient.
Versuchen Sie als Übung, eine externe Bibliothek zu erstellen und in einer Konsolenanwendung zu verwenden, ändern Sie dann die Werte in der Bibliothek und kompilieren Sie sie neu (ohne das Consumer-Programm neu zu kompilieren), legen Sie die DLL in dem Verzeichnis ab und führen Sie die EXE-Datei manuell aus dass sich die konstante Zeichenfolge nicht ändert.
quelle
Konstante
Wir müssen den Wert für das const-Feld bereitstellen, wenn es definiert ist. Der Compiler speichert dann den Wert der Konstante in den Metadaten der Assembly. Dies bedeutet, dass eine Konstante nur für den primitiven Typ wie Boolescher Wert, Zeichen, Byte usw. definiert werden kann. Konstanten werden immer als statische Elemente betrachtet, nicht als Instanzmitglieder.
Schreibgeschützt
Schreibgeschützte Felder können nur zur Laufzeit aufgelöst werden. Das heißt, wir können einen Wert für einen Wert mithilfe des Konstruktors für den Typ definieren, in dem das Feld deklariert ist. Die Überprüfung wird vom Compiler durchgeführt, dass schreibgeschützte Felder von keiner anderen Methode als dem Konstruktor beschrieben werden.
Mehr zu beiden hier in diesem Artikel erklärt
quelle
Hauptsächlich; Sie können einem statischen schreibgeschützten Feld zur Laufzeit einen Wert für einen nicht konstanten Wert zuweisen, während einer Konstante ein konstanter Wert zugewiesen werden muss.
quelle
Const und Readonly sind ähnlich, aber sie sind nicht genau gleich. Ein const-Feld ist eine Konstante zur Kompilierungszeit, was bedeutet, dass dieser Wert zur Kompilierungszeit berechnet werden kann. Ein schreibgeschütztes Feld ermöglicht zusätzliche Szenarien, in denen während der Erstellung des Typs Code ausgeführt werden muss. Nach der Erstellung kann ein schreibgeschütztes Feld nicht mehr geändert werden.
Zum Beispiel können const-Mitglieder verwendet werden, um Mitglieder wie folgt zu definieren:
da Werte wie 3.14 und 0 Konstanten zur Kompilierungszeit sind. Betrachten Sie jedoch den Fall, in dem Sie einen Typ definieren und einige vorgefertigte Instanzen davon bereitstellen möchten. Beispielsweise möchten Sie möglicherweise eine Farbklasse definieren und "Konstanten" für gängige Farben wie Schwarz, Weiß usw. bereitstellen. Dies ist mit const-Elementen nicht möglich, da die rechten Seiten keine Konstanten zur Kompilierungszeit sind. Man könnte dies mit regulären statischen Mitgliedern tun:
Aber dann gibt es nichts, was einen Kunden von Color davon abhält, sich damit zu beschäftigen, vielleicht indem er die Schwarz-Weiß-Werte vertauscht. Dies würde natürlich andere Kunden der Color-Klasse bestürzen. Die Funktion "Nur Lesen" behebt dieses Szenario. Indem wir einfach das schreibgeschützte Schlüsselwort in die Deklarationen einfügen, behalten wir die flexible Initialisierung bei und verhindern gleichzeitig, dass Client-Code herumwirbelt.
Es ist interessant festzustellen, dass const-Elemente immer statisch sind, während ein schreibgeschütztes Element entweder statisch sein kann oder nicht, genau wie ein reguläres Feld.
Es ist möglich, ein einzelnes Schlüsselwort für diese beiden Zwecke zu verwenden, dies führt jedoch entweder zu Versionsproblemen oder zu Leistungsproblemen. Nehmen wir für einen Moment an, dass wir ein einziges Schlüsselwort für dieses (const) verwendet haben und ein Entwickler schrieb:
und ein anderer Entwickler schrieb Code, der sich auf A stützte:
Kann der generierte Code nun auf der Tatsache beruhen, dass AC eine Konstante zur Kompilierungszeit ist? Kann die Verwendung von AC einfach durch den Wert 0 ersetzt werden? Wenn Sie dazu "Ja" sagen, bedeutet dies, dass der Entwickler von A die Art und Weise, wie AC initialisiert wird, nicht ändern kann - dies bindet die Hände des Entwicklers von A ohne Erlaubnis. Wenn Sie zu dieser Frage "Nein" sagen, wird eine wichtige Optimierung übersehen. Vielleicht ist der Autor von A sicher, dass AC immer Null sein wird. Die Verwendung von const und readonly ermöglicht es dem Entwickler von A, die Absicht anzugeben. Dies sorgt für ein besseres Versionsverhalten und eine bessere Leistung.
quelle
ReadOnly: Der Wert wird nur einmal vom Konstruktor der Klasse initialisiert.
const: kann in jeder Funktion nur einmal initialisiert werden
quelle
Der Unterschied besteht darin, dass der Wert eines statischen schreibgeschützten Felds zur Laufzeit festgelegt wird, sodass es für verschiedene Programmausführungen einen anderen Wert haben kann. Der Wert eines const-Feldes wird jedoch auf eine Kompilierungszeitkonstante gesetzt.
Denken Sie daran: Bei Referenztypen verhindert der schreibgeschützte Modifikator in beiden Fällen (statisch und instanziell) nur, dass Sie dem Feld eine neue Referenz zuweisen. Insbesondere macht es das Objekt, auf das in der Referenz verwiesen wird, nicht unveränderlich.
Weitere Informationen finden Sie unter Häufig gestellte C # -Fragen zu diesem Thema: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx
quelle
Konstante Variablen werden zur Kompilierungszeit deklariert und initialisiert. Der Wert kann nach den Stationen nicht mehr geändert werden. Schreibgeschützte Variablen werden nur vom statischen Konstruktor der Klasse initialisiert. Schreibgeschützt wird nur verwendet, wenn der Wert zur Laufzeit zugewiesen werden soll.
quelle
Konst : Absoluter konstanter Wert während des Anwendungslebenszeit.
Readonly : Kann in der Laufzeit geändert werden.
quelle
Eine Sache, die man zu dem hinzufügen sollte, was die Leute oben gesagt haben. Wenn Sie eine Assembly haben, die einen schreibgeschützten Wert enthält (z. B. readonly MaxFooCount = 4;), können Sie den Wert ändern, den aufrufende Assemblys sehen, indem Sie eine neue Version dieser Assembly mit einem anderen Wert versenden (z. B. readonly MaxFooCount = 5;).
Aber mit einer Konstante würde es beim Kompilieren des Anrufers in den Code des Anrufers gefaltet.
Wenn Sie dieses Niveau der C # -Kompetenz erreicht haben, sind Sie bereit für Bill Wagners Buch Effective C #: 50 spezifische Möglichkeiten zur Verbesserung Ihres C #, das diese Frage ausführlich beantwortet (und 49 andere Dinge).
quelle