1595 Stimmen

'Statisch schreibgeschützt' vs. 'const'

Ich habe mich über const und static readonly Felder informiert. Wir haben einige Klassen, die nur konstante Werte enthalten. Sie werden für verschiedene Dinge in unserem System verwendet. Daher frage ich mich, ob meine Beobachtung korrekt ist:

Sollten diese Art von konstanten Werten immer static readonly sein für alles, was öffentlich ist? Und nur const für internal/protected/private Werte verwenden?

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

8 Stimmen

Hier ist ein sehr interessanter Einzelfall, den ich gerade zugunsten von static readonly gefunden habe: Versuchen Sie, ein const innerhalb eines IEnumerator zu verwenden, das ein unerreichbares yield auslösen würde, und Sie erhalten einen gefürchteten "Interner Compilerfehler". Ich habe den Code nicht außerhalb von Unity3D getestet, aber ich vertraue darauf, dass dies entweder ein Mono oder ein .NET Fehler ist. Es handelt sich jedoch um ein C# Problem.

4 Stimmen

10 Stimmen

Eine weitere Unterschied besteht darin, dass Sie eine const-Zeichenfolge in einem Switch verwenden können, aber keine static readonly-Zeichenfolge.

1072voto

Marc Gravell Punkte 970173

public static readonly Felder sind etwas ungewöhnlich; public static Eigenschaften (mit nur einem get) wären häufiger (vielleicht unterstützt durch ein private static readonly Feld).

const Werte werden direkt in die Aufrufstelle eingebrannt; das hat zwei Seiten:

  • es ist nutzlos, wenn der Wert zur Laufzeit abgerufen wird, vielleicht aus der Konfiguration
  • wenn Sie den Wert einer Konstanten ändern, müssen alle Clients neu erstellt werden
  • aber es kann schneller sein, da ein Methodenaufruf vermieden wird...
  • ...der möglicherweise ohnehin vom JIT inline geschaltet wurde

Wenn der Wert sich niemals ändern wird, dann ist const in Ordnung - Zero usw. sind vernünftige Konstanten ;p Ansonsten sind static Eigenschaften häufiger.

18 Stimmen

Warum eine Eigenschaft über ein Feld? Wenn es sich um eine unveränderliche Klasse handelt, sehe ich keinen Unterschied.

85 Stimmen

@Michael - aus den gleichen Gründen wie immer; es verbirgt die Implementierung. Möglicherweise stellen Sie (später) fest, dass Sie lazy loaded sein müssen, konfigurationsbasiert, eine Fassade oder was auch immer. In Wirklichkeit wäre entweder oft in Ordnung...

0 Stimmen

Was bedeutet es, wenn die Konstante zur Laufzeit nutzlos ist? Kann die Laufzeit Konstanten nicht lesen, die Schlüsselwerte aus einer app.config oder web.config ziehen?

284voto

Michael Stum Punkte 172055

Ich würde static readonly verwenden, wenn der Consumer in einer anderen Assembly ist. Wenn const und der Consumer in zwei verschiedenen Assemblies sind, ist das eine gute Möglichkeit, sich selbst ins Bein zu schießen.

8 Stimmen

So wie einige erwähnt oder angedeutet haben, könnte es klug sein, const nur für Werte zu verwenden, die tatsächlich bekannte Konstanten sind, wenn sie öffentlich gemacht werden, sollten sie sonst für interne, geschützte oder private Zugriffsbereiche reserviert sein.

2 Stimmen

@Dio Der Grund, warum es noch vorhanden ist, liegt daran, dass es an sich kein Problem darstellt - es ist etwas, worüber man sich im Klaren sein sollte, aber die Möglichkeit, Konstanten über Assembly-Grenzen hinweg einzubetten, ist eine gute Sache für die Leistungsfähigkeit. Es geht wirklich nur darum, wirklich zu verstehen, dass "Konstante" bedeutet "es wird sich nie ändern".

1 Stimmen

@MichaelStum Ok, ich sollte es nicht "ein Problem" nennen. In meinem Arbeitsbereich habe ich Konstanten und teile sie über Assemblys hinweg, aber ich kompiliere sie für jede Bereitstellung oder Codeverschiffung erneut. Dennoch ist dieser Fakt definitiv erwähnenswert.

228voto

Peter Punkte 45640

Ein paar weitere relevante Punkte, die beachtet werden müssen:

const int a

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

readonly int a

  • kann einen Standardwert verwenden, ohne initialisiert zu werden.
  • Initialisierung kann zur Ausführungszeit erfolgen (Bearbeitung: nur im Konstruktor).

46 Stimmen

Innerhalb des ctor nur.

4 Stimmen

Nicht nur innerhalb des Konstruktors, sondern auch bei der Deklaration (learn.microsoft.com/de-de/dotnet/csharp/language-reference/‌​…).

222voto

Jeppe Stig Nielsen Punkte 57056

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 eine const und eine 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, während:

static readonly int y = 42;

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

False ausgibt.

Der Grund dafür ist, dass die Methode x.Equals zwei Überladungen hat, eine, die einen short (System.Int16) und eine, die ein object (System.Object) annimmt. Jetzt stellt sich die Frage, ob eine oder beide mit meinem y-Argument übereinstimmen.

Wenn y ein Kompilierzeitkonstante (Literal) ist, der const-Fall, wird es wichtig, dass eine implizite Konvertierung von int nach short vorhanden ist, vorausgesetzt, dass die int eine Konstante ist und der C#-Compiler überprüft, ob der Wert im Bereich eines short liegt (was bei 42 der Fall ist). Siehe Implizite Konstantenausdruckskonvertierungen in der C#-Sprachspezifikation. Also müssen beide Überladungen berücksichtigt werden. Die Überladung Equals(short) wird bevorzugt (jedes short ist ein object, aber nicht alle object sind short). Daher wird y in ein short konvertiert und diese Überladung verwendet. Dann vergleicht Equals zwei short von identischem Wert, was zu true führt.

Wenn y keine Konstante ist, existiert keine implizite Konvertierung von int nach short. Das liegt daran, dass im Allgemeinen ein int zu groß sein kann, um in ein short zu passen. (Eine explizite Konvertierung existiert, aber ich habe nicht Equals((short)y) gesagt, daher ist das nicht relevant.) Wir sehen, dass nur eine Überladung zutrifft, die Equals(object). Daher wird y in ein object geboxt. Dann vergleicht Equals ein System.Int16 mit einem System.Int32, und da die Laufzeittypen nicht übereinstimmen, ergibt das false.

Wir kommen zu dem Schluss, dass in einigen (seltenen) Fällen die Änderung eines const-Typmembers in ein static readonly Feld (oder umgekehrt, wenn das möglich ist) das Verhalten des Programms ändern kann.

22 Stimmen

Eine gute Ergänzung zur akzeptierten Antwort. Ich würde gerne hinzufügen, dass die ordnungsgemäße Konvertierung von Datentypen und ähnliche Richtlinien (wie z.B. Try-Catch-Blöcke etc.) ein fester Bestandteil erfahrener Programmierer sein sollte und nicht dem Compiler überlassen werden sollte. Trotzdem habe ich hier etwas Neues gelernt. Vielen Dank.

3 Stimmen

Wow, ich programmiere schon lange in C# und hätte nie gedacht, dass ein const int im Bereich eines short implizit in ein short umgewandelt werden könnte. Ich muss sagen, das ist ziemlich seltsam. Ich liebe C#, aber diese seltsamen Inkonsistenzen, die nicht viel Wert zu haben scheinen, aber viel Gehirnkapazität erfordern, um sie ständig zu berücksichtigen, können ärgerlich sein, insbesondere für Anfänger.

4 Stimmen

@MikeMarynowski Stimmt schon. Aber ich denke, sie haben diese Regel (unter anderem) aufgestellt, um die Aussage short x = 42; legal zu machen. Denn dort haben Sie ein int, nämlich das Literal 42, das implizit in das short x umgewandelt wird. Aber dann haben sie das möglicherweise auf numerische Literale beschränkt; jedoch haben sie sich dafür entschieden, auch Dinge wie short x = y; zuzulassen, wobei y definiert ist als const int y = 42;, und so sind sie dann darauf gekommen.

101voto

Chris S Punkte 63542

Eines ist zu beachten, const ist auf primitive/Werttypen beschränkt (mit Ausnahme von Zeichenketten).

33 Stimmen

Eigentlich könnte const auch für andere Typen verwendet werden, außer dass es mit null initialisiert werden muss, was es nutzlos macht :)

6 Stimmen

Ausnahme wie in System.Exception? :)

6 Stimmen

@nawfal Genauer gesagt sind die einzigen Werttypen, für die const verwendet werden kann, sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool sowie alle enum Typen. const kann nicht für andere Werttypen wie DateTime oder TimeSpan oder BigInteger verwendet werden. Es kann auch nicht für die Struktur IntPtr verwendet werden (von einigen als "primitive" Typ betrachtet; der Begriff "primitive Typ" ist in C# verwirrend). Das const kann für alle Referenztypen verwendet werden. Wenn der Typ string ist, kann jeder Zeichenfolgenwert angegeben werden. Andernfalls muss der Wert null sein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X