Was ist der Unterschied zwischen const
und readonly
in C #?
Wann würden Sie eins über das andere verwenden?
Was ist der Unterschied zwischen const
und readonly
in C #?
Wann würden Sie eins über das andere verwenden?
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 eine ClassName.ConstantName
Notation, um darauf zuzugreifen.Es gibt einen subtilen Unterschied. Betrachten Sie eine Klasse, die in definiert ist AssemblyA
.
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly int I_RO_VALUE;
public Const_V_Readonly()
{
I_RO_VALUE = 3;
}
}
AssemblyB
verweist AssemblyA
und verwendet diese Werte im Code. Wenn dies kompiliert ist,
const
Wertes ist es wie ein Suchen-Ersetzen, der Wert 2 wird in die AssemblyB
IL des 'eingebrannt' . Dies bedeutet, dass ich morgen I_CONST_VALUE
auf 20 aktualisieren werde . AssemblyB
hätte noch 2 bis ich es neu kompiliere .readonly
Wertes ist es wie ref
ein Speicherort. Der Wert wird nicht in AssemblyB
die IL eingebrannt . Dies bedeutet, dass bei einer Aktualisierung des Speicherorts AssemblyB
der neue Wert ohne Neukompilierung abgerufen wird . Wenn I_RO_VALUE
also 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
.
public const int 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
.
public readonly float 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
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 ändern string.Empty
zu "Hello, world!"
, aber ich würde behaupten , noch nicht , dass dies macht string.Empty
modifizierbar, oder dass Code sollte nicht davon ausgehen , dass string.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!
Nur um hinzuzufügen, macht ReadOnly für Referenztypen nur die Referenz schreibgeschützt, nicht die Werte. Zum Beispiel:
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};
public UpdateReadonly()
{
I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
I_RO_VALUE = new char[]{'V'}; //will cause compiler error
}
}
string
, den Sie als Konstante verwenden könnten?
const
mit anderen Referenztypen als Zeichenfolge haben, aber die Konstante kann nur den Wert haben null
.
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.
public class Sample {
private readonly string ro;
public Sample() {
ro = "set";
}
public Sample(string value) : 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 const
Schlüsselwort als Feld deklariert und müssen beim Deklarieren initialisiert werden.
public class MyClass
{
public const double PI1 = 3.14159;
}
Ein readonly
Mitglied ist insofern wie eine Konstante, als es einen unveränderlichen Wert darstellt. Der Unterschied besteht darin, dass ein readonly
Mitglied zur Laufzeit in einem Konstruktor initialisiert werden kann und auch beim Deklarieren initialisiert werden kann.
public class MyClass1
{
public readonly double PI2 = 3.14159;
//or
public readonly double PI3;
public MyClass2()
{
PI3 = 3.14159;
}
}
const
static
(sie sind implizit statisch).schreibgeschützt
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
Hier ist ein weiterer Link, der zeigt, dass const nicht versionssicher oder für Referenztypen relevant ist.
Zusammenfassung :
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).
Noch ein Gotcha: Readonly-Werte können durch "verschlagenen" Code durch Reflexion geändert werden.
var fi = this.GetType()
.BaseType
.GetField("_someField",
BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);
Kann ich ein privates schreibgeschütztes geerbtes Feld in C # mithilfe von Reflection ändern?
Ich glaube, ein const
Wert ist für alle Objekte gleich (und muss mit einem wörtlichen Ausdruck initialisiert werden), während er readonly
für jede Instanziierung unterschiedlich sein kann ...
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.
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:
public static class Text {
public const string ConstDescription = "This can be used.";
public readonly static string ReadonlyDescription = "Cannot be used.";
}
public class Foo
{
[Description(Text.ConstDescription)]
public int BarThatBuilds {
{ get; set; }
}
[Description(Text.ReadOnlyDescription)]
public int BarThatDoesNotBuild {
{ get; set; }
}
}
wann zu verwenden const
oderreadonly
const
readonly
App.config
Initialisierung kann sie nicht mehr geändert werdenMit 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.
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ß).
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.
public const DateTime dt = DateTime.Today; //throws compilation error
public const string Name = string.Empty; //throws compilation error
public readonly string Name = string.Empty; //No error, legal
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
{
public readonly int Id;
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.
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
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:
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
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:
public class Color
{
public static Color Black = new Color(0, 0, 0);
public static Color White = new Color(255, 255, 255);
public static Color Red = new Color(255, 0, 0);
public static Color Green = new Color(0, 255, 0);
public static Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(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.
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(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:
public class A
{
public static const C = 0;
}
und ein anderer Entwickler schrieb Code, der sich auf A stützte:
public class B
{
static void Main() {
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.
Weitere Informationen finden Sie unter Häufig gestellte C # -Fragen zu diesem Thema: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx
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.
Konst : Absoluter konstanter Wert während des Anwendungslebenszeit.
Readonly : Kann in der Laufzeit geändert werden.
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).