it-swarm.com.de

Statisch readonly vs const

Ich habe über const und static readonly Felder gelesen. Wir haben einige Klassen, die nur konstante Werte enthalten. Wird für verschiedene Dinge in unserem System verwendet. Ich frage mich also, ob meine Beobachtung richtig ist:

Sollten diese konstanten Werte für alles, was öffentlich ist, immer static readonly sein? Und const nur für interne/geschützte/private Werte verwenden?

Was empfehlen Sie? Sollte ich vielleicht sogar keine static readonly -Felder verwenden, sondern Eigenschaften verwenden?

1321
Svish

public static readonly Felder sind etwas ungewöhnlich; public static -Eigenschaften (mit nur einem get) wären häufiger (möglicherweise durch ein private static readonly -Feld gesichert).

const Werte werden direkt in die Call-Site eingebrannt; Das ist zweischneidig:

  • es ist nutzlos, wenn der Wert zur Laufzeit abgerufen wird, möglicherweise aus config
  • wenn Sie den Wert einer Konstante ändern, müssen Sie alle Clients neu erstellen
  • aber es kann schneller sein, da es einen Methodenaufruf vermeidet ...
  • ... die manchmal sowieso von der GEG übernommen wurden

Wenn sich der Wert nie ändert, ist const in Ordnung - Zero etc macht sinnvolle consts; p Abgesehen davon sind static -Eigenschaften häufiger.

909
Marc Gravell

Ich würde static readonly verwenden, wenn sich der Consumer in einer anderen Assembly befindet. Den const und den Consumer in zwei verschiedenen Baugruppen zu haben, ist eine gute Möglichkeit, sich in den Fuß zu schießen .

230
Michael Stum

Einige relevantere Dinge, die zu beachten sind:

const int a

  • muss initialisiert werden.
  • die Initialisierung muss zur Kompilierzeit erfolgen .

readonly int a

  • kann einen Standardwert verwenden, ohne zu initialisieren.
  • die Initialisierung kann zur Laufzeit erfolgen (Bearbeiten: nur innerhalb des Konstruktors).
193
Peter

Dies ist nur eine Ergänzung zu den anderen Antworten. Ich werde sie nicht wiederholen (jetzt vier Jahre später).

Es gibt Situationen, in denen ein const und ein nicht-const unterschiedliche Semantiken haben. Zum Beispiel:

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

gibt True aus, wobei:

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

schreibt False.

Der Grund dafür ist, dass die Methode x.Equals zwei Überladungen hat, eine, die eine short (System.Int16) Und eine, die eine object (System.Object). Nun stellt sich die Frage, ob einer oder beide mit meinem Argument y zutreffen.

Wenn y eine Konstante zur Kompilierungszeit (Literal) ist, wird es im Fall const wichtig, dass eine implizite Konvertierung vorhanden ist fromint toshort vorausgesetzt, dass int eine Konstante ist und dass der C # -Compiler überprüft, ob sein Wert im Bereich von short (welches 42 Ist). Siehe Implizite Konvertierungen von Konstantenausdrücken in der C # -Sprachenspezifikation. Es müssen also beide Überlastungen berücksichtigt werden. Die Überladung Equals(short) wird bevorzugt (jedes short ist ein object, aber nicht alle object sind short). Also wird y in short konvertiert und diese Überladung wird verwendet. Dann vergleicht Equals zwei short mit identischem Wert, und das ergibt true.

Wenn y keine Konstante ist, gibt es keine implizit Konvertierung von int nach short. Dies liegt daran, dass ein int im Allgemeinen zu groß sein kann, um in ein short zu passen. (Eine explizit Konvertierung existiert, aber ich habe Equals((short)y) nicht gesagt, das ist also nicht relevant.) Wir sehen, dass nur eine Überladung zutrifft, die Equals(object) einer. Daher wird y in object eingeschlossen. Dann vergleicht Equals einen System.Int16 Mit einem System.Int32, Und da die Laufzeitarten nicht einmal übereinstimmen, ergibt sich false.

Wir schließen daraus, dass in einigen (seltenen) Fällen das Ändern eines Members vom Typ const in ein Feld vom Typ static readonly (Oder auf andere Weise, wenn dies möglich ist) das Verhalten des Programms ändern kann.

170

Zu beachten ist, dass const auf Primitiv-/Werttypen beschränkt ist (Ausnahme: Zeichenfolgen).

87
Chris S

Das Schlüsselwort readonly unterscheidet sich vom Schlüsselwort const. Ein const -Feld kann nur bei der Deklaration des Feldes initialisiert werden. Ein readonly -Feld kann entweder bei der Deklaration oder in einem Konstruktor initialisiert werden. Daher können readonly Felder je nach verwendetem Konstruktor unterschiedliche Werte haben. Während ein const -Feld eine Konstante zur Kompilierungszeit ist, kann das readonly -Feld auch für Laufzeitkonstanten verwendet werden

Kurzer und klarer MSDN-Verweis hier

25
yazanpro

Statisch Schreibgeschützt : Der Wert kann zur Laufzeit über den Konstruktor static geändert werden. Aber nicht über die Mitgliederfunktion.

Konstante : Standardmäßig static. Der Wert kann von keiner Stelle aus geändert werden (Ctor, Function, Runtime usw. no-where).

Schreibgeschützt : Der Wert kann zur Laufzeit über den Konstruktor geändert werden. Aber nicht über die Mitgliederfunktion.

Sie können sich mein Repo ansehen: C # -Eigenschaftstypen .

22

const und readonly sind ähnlich, aber nicht genau gleich.

Ein const -Feld ist eine Konstante zur Kompilierungszeit, was bedeutet, dass dieser Wert zur Kompilierungszeit berechnet werden kann. Ein readonly -Feld ermöglicht zusätzliche Szenarien, in denen während der Erstellung des Typs Code ausgeführt werden muss. Nach der Erstellung kann ein readonly -Feld nicht geändert werden.

Beispielsweise können const Mitglieder verwendet werden, um Mitglieder wie die folgenden 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 Color-Klasse definieren und "Konstanten" für allgemeine Farben wie Schwarz, Weiß usw. bereitstellen. Dies ist mit const-Elementen nicht möglich, da die rechten Seiten keine Konstanten zur Kompilierungszeit sind. Dies könnte man mit regulären statischen Mitgliedern machen:

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, green, blue) = (r, g, b);
}

Aber dann gibt es nichts, was einen Kunden von Color davon abhält, sich damit zu beschäftigen, vielleicht durch Vertauschen der Schwarz- und Weißwerte. Selbstverständlich würde dies bei anderen Clients der Color-Klasse Bestürzung auslösen. Die "readonly" -Funktion behebt dieses Szenario.

Durch einfaches Einfügen des Schlüsselworts readonly in die Deklarationen wird die flexible Initialisierung beibehalten und gleichzeitig verhindert, dass sich der 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, green, blue) = (r, g, b);
}

Es ist interessant festzustellen, dass const-Member immer statisch sind, wohingegen ein readonly-Member 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 zu Versions- oder Leistungsproblemen. Nehmen wir für einen Moment an, dass wir ein einzelnes 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 sich der generierte Code darauf verlassen, dass A.C eine Konstante zur Kompilierungszeit ist? D. h., Kann die Verwendung von Wechselstrom einfach durch den Wert 0 ersetzt werden? Wenn Sie dazu "Ja" sagen, bedeutet dies, dass der Entwickler von A die Art und Weise, wie A.C 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 sich der Autor von A sicher, dass A.C immer Null sein wird. Die Verwendung von const und readonly ermöglicht es dem Entwickler von A, die Absicht anzugeben. Dies führt zu einem besseren Versionsverhalten und einer besseren Leistung.

15

Ich bevorzuge es, const zu verwenden, wann immer ich kann, was, wie oben erwähnt, auf wörtliche Ausdrücke oder etwas beschränkt ist, das keine Auswertung erfordert.

Wenn ich gegen diese Einschränkung angehe, greife ich mit einer Einschränkung auf static readonly zurück. Ich würde im Allgemeinen eine öffentliche statische Eigenschaft mit einem Getter und einem schreibgeschützten privaten statischen Feld verwenden, wie Marc erwähnt hier .

12
Peter Meyer

Const: Const ist nichts anderes als "Konstante", eine Variable, deren Wert aber zur Kompilierungszeit konstant ist. Und es ist obligatorisch, einen Wert zuzuweisen. Standardmäßig ist eine const statisch und wir können den Wert einer const-Variablen nicht im gesamten Programm ändern.

Static ReadOnly: Der Wert einer Variablen vom Typ Static Readonly kann zur Laufzeit zugewiesen oder zur Kompilierungszeit zugewiesen und zur Laufzeit geändert werden. Der Wert dieser Variablen kann jedoch nur im statischen Konstruktor geändert werden. Und kann nicht weiter geändert werden. Sie kann zur Laufzeit nur einmal geändert werden

Hinweis: c-scharfe Ecke

7
mayank

Ein statisches schreibgeschütztes Feld ist vorteilhaft, wenn Sie anderen Assemblys einen Wert zur Verfügung stellen, der sich in einer späteren Version ändern kann.

Angenommen, Assembly X macht eine Konstante wie folgt verfügbar:

public const decimal ProgramVersion = 2.3;

Wenn Assembly Y auf X verweist und diese Konstante verwendet, wird der Wert 2.3 beim Kompilieren in Assembly Y gebacken. Das heißt, wenn X später mit der Konstante 2.4 neu kompiliert wird, verwendet Y immer noch den alten Wert 2.3, bis Y neu kompiliert wird. Ein statisches schreibgeschütztes Feld vermeidet dieses Problem.

Eine andere Sichtweise ist, dass jeder Wert, der sich in Zukunft ändern könnte, nicht per Definition konstant ist und daher nicht als einer dargestellt werden sollte.

6
Yagnesh Cangi

const:

  1. wert sollte bei der Deklaration angegeben werden
  2. zeitkonstante kompilieren

schreibgeschützt:

  1. value kann bei der Deklaration oder zur Laufzeit mit Hilfe von Konstruktoren angegeben werden. Der Wert kann je nach verwendetem Konstruktor variieren.
  2. laufzeitkonstante
3
dasumohan89

Const : const-Variablenwerte müssen zusammen mit der Deklaration definiert werden, danach ändert sich nichts mehr. const sind implizit static, damit wir auf sie zugreifen können, ohne eine Klasseninstanz zu erstellen. Dies hat zur Kompilierungszeit einen Wert

ReadOnly : Nur lesbare Variablenwerte, die wir definieren können, während wir deklarieren und den Konstruktor zur Laufzeit verwenden. schreibgeschützte Variablen können ohne Klasseninstanz nicht zugreifen.

Statisch schreibgeschützt : statische schreibgeschützte Variablenwerte, die wir beim Deklarieren definieren können, sowie nur über einen statischen Konstruktor, aber nicht mit einem anderen Konstruktor. Auf diese Variablen können wir auch zugreifen ohne Klasseninstanz zu erstellen (als statische Variablen).

statisch schreibgeschützt ist die bessere Wahl, wenn die Variablen in verschiedenen Assemblys verwendet werden müssen. Bitte überprüfen Sie die vollständigen Details im folgenden Link

https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yourself-in-the-foot/

3
user1756922

In C # .Net gibt es einen geringfügigen Unterschied zwischen const- und statischen schreibgeschützten Feldern

const muss zur Kompilierungszeit mit value initialisiert werden.

const ist standardmäßig statisch und muss mit einem konstanten Wert initialisiert werden, der später nicht mehr geändert werden kann. Es kann nicht mit allen Datentypen verwendet werden. Zum Beispiel DateTime. Sie kann nicht mit DateTime-Datentypen verwendet werden.

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public static readonly string Name = string.Empty; //No error, legal

readonly kann als statisch deklariert werden, ist aber nicht notwendig. Zum Zeitpunkt der Deklaration ist keine Initialisierung erforderlich. Sein Wert kann einmalig mit einem Konstruktor zugewiesen oder geändert werden. Es gibt also die Möglichkeit, den Wert eines schreibgeschützten Feldes einmal zu ändern (egal, ob es statisch ist oder nicht), was mit const nicht möglich ist.

2
Chirag

Konstanten sind, wie der Name schon sagt, Felder, die sich nicht ändern und normalerweise zur Kompilierungszeit im Code statisch definiert werden.

Schreibgeschützte Variablen sind Felder, die sich unter bestimmten Bedingungen ändern können.

Sie können entweder initialisiert werden, wenn Sie sie zum ersten Mal als Konstante deklarieren. Normalerweise werden sie jedoch während der Objektkonstruktion innerhalb des Konstruktors initialisiert.

Sie können nach der Initialisierung unter den oben genannten Bedingungen nicht mehr geändert werden.

Statisches Nur-Lesen klingt für mich nach einer schlechten Wahl, da es sich, wenn es statisch ist und sich nie ändert, nur um eine öffentliche Konstante handelt. Wenn es sich ändern kann, ist es keine Konstante. Abhängig von Ihren Anforderungen können Sie entweder read verwenden -nur oder nur eine reguläre Variable.

Ein weiterer wichtiger Unterschied ist, dass eine Konstante zur Klasse gehört, während die schreibgeschützte Variable zur Instanz gehört!

0