Frage

Compilerfehler CS0283 zeigt an, dass nur die Grund POD-Typen (sowie Streicher, Aufzählungen und null Referenzen) als const deklariert werden. Hat jemand eine Theorie über die Gründe für diese Einschränkung haben? Zum Beispiel wäre es schön, in der Lage sein zu konst Werten anderer Typen, wie IntPtr zu deklarieren.

Ich glaube, dass das Konzept der const tatsächlich syntaktischer Zucker in C # ist, und dass es ersetzt nur alle Verwendungen des Namen mit dem Literalwert. Zum Beispiel angesichts der folgenden Erklärung, jede Bezugnahme auf Foo würde mit „foo“ bei der Kompilierung ersetzt werden.

const string Foo = "foo";

Dies würde keine änderbaren Typen ausschließen, vielleicht wählten sie diese Einschränkung anstatt zum Zeitpunkt der Kompilierung, um zu bestimmen, ob ein bestimmte Typ wandelbar ist?

War es hilfreich?

Lösung

Aus der C # Spezifikation, Kapitel 10.4 - Konstanten :
(10.4 in der C # 3.0-Spezifikation, 10,3 in der Online-Version für 2.0)

  

Eine Konstante ist ein Klassenmitglied, das einen konstanten Wert darstellt. Einen Wert, der zum Zeitpunkt der Kompilierung berechnet werden kann

Das sagt im Grunde, dass Sie nur Ausdrücke verwenden können, die ausschließlich aus Literalen besteht. Alle Anrufe auf alle Methoden, Konstruktoren (das kann nicht als reine IL-Literale dargestellt werden) kann nicht verwendet werden, da es keine Möglichkeit für den Compiler, dass die Ausführung zu tun, und somit die Ergebnisse berechnen, bei der Kompilierung. Auch kann, da es keine Möglichkeit gibt, ein Verfahren als invariant zu markieren (dh. Es gibt eine Eins-zu-Eins-Abbildung zwischen Eingang und Ausgang), ist die einzige Möglichkeit für den Compiler, dies zu tun, wäre, entweder die IL zu analysieren, um zu sehen, ob es hängt von anderen Dingen als die Eingabeparameter, spezielle-Fall einiger Arten behandeln (wie IntPtr), oder einfach nur jeden Anruf zu jedem Code nicht zulassen.

IntPtr, als ein Beispiel, wenn auch ein Werttyp ist, ist immer noch eine Struktur, und nicht eine des eingebauten in Literale. Als solche jeder Ausdruck einen IntPtr verwenden, muß Code in der IntPtr Struktur nennen, und das ist, was für eine konstante Erklärung nicht legal ist.

Das einzige legale konstanter Wert Typ Beispiel, das ich denken kann, würde eine sein, die durch nur erklärt es mit Nullen initialisiert wird, und das ist kaum sinnvoll.

Was, wie der Compiler behandelt / verwendet Konstanten, wird es den berechneten Wert anstelle des konstanten Namen im Code verwenden.

So haben Sie folgende Wirkung:

  • Kein Verweis auf den ursprünglichen Konstante Namen, Klasse wurde in deklariert oder ein Namespace, wird an dieser Stelle in den Code kompiliert
  • Wenn Sie den Code dekompilieren, wird es magische Zahlen in sie haben, nur weil der ursprüngliche „Referenz“ auf die konstant ist, wie oben erwähnt, nicht vorhanden ist, wird nur der Wert der Konstanten
  • Der Compiler kann diese nutzen zu optimieren oder sogar entfernen, unnötigen Code. Zum Beispiel if (SomeClass.Version == 1), wenn SomeClass.Version den Wert 1 hat, wird in der Tat entfernen Sie die if-Anweisung, und halten Sie den Code-Block ausgeführt wird. Wenn der Wert der Konstanten nicht 1 ist, dann ist die ganze if-Anweisung und deren Block werden entfernt.
  • Da der Wert einer Konstante in den Code kompiliert wird, und nicht einen Verweis auf die Konstante, Konstanten aus anderen Baugruppen mit dem kompilierten Code in irgendeiner Weise nicht automatisch aktualisiert werden, wenn der Wert der Konstanten ändern sollte (was es sein sollte nicht!)

Mit anderen Worten, mit dem folgende Szenario:

  1. Assembly A, enthält eine Konstante mit dem Namen "Version" einen Wert von 1
  2. Assembly B enthält einen Ausdruck, der die Versionsnummer der Baugruppe A von dieser Konstante analysiert und vergleicht sie mit 1, um sicherzustellen, dass es mit der Montage arbeitet
  3. Jemand Baugruppe A ändert, um den Wert der Konstanten zum 2 und Neuaufbau A (aber nicht B)

In diesem Fall Baugruppe B, in seiner kompilierter Form, noch den Wert von 1 zu 1 vergleichen, denn wenn B kompiliert wurde, die konstant den Wert 1 hatte.

In der Tat, wenn das die einzige Verwendung von irgendetwas von der Montage A in Baugruppe B ist, wird die Montage B ohne eine Abhängigkeit von Baugruppe A kompiliert werden Ausführen der Code enthält, dass die Expression in der Montage B nicht Baugruppe A geladen werden.

Konstanten sollten daher nur für Dinge verwendet werden, die sich nie ändern wird. Wenn es ein Wert ist, der könnte oder wird noch einige Zeit in der Zukunft ändern, und Sie können nicht garantieren, dass alle andere Baugruppen gleichzeitig wieder aufgebaut werden, ein Nur-Lese-Feld ist besser geeignet als eine Konstante.

Das ist also ok:

  • public const Int32 NumberOfDaysInAWeekInGregorianCalendar = 7;
  • public const Int32 NumberOfHoursInADayOnEarth = 24;

, während dies nicht:

  • public const Int32AgeOfProgrammer = 25;
  • public const String NameOfLastProgrammerThatModifiedAssembly = "Joe Programmer";

Bearbeiten 27. Mai 2016

OK, habe gerade eine upvote, so dass ich wieder lesen Sie meine Antwort hier und das ist eigentlich etwas falsch.

Nun wird die Absicht der Sprache C # Spezifikation ist alles, was ich oben geschrieben habe. Sie sind nicht angeblich etwas zu verwenden, die nicht mit einem wörtlichen als const dargestellt werden kann.

Aber können Sie? Nun ja ....

Lassen Sie uns einen Blick auf die decimal Art.

public class Test
{
    public const decimal Value = 10.123M;
}

Schauen wir uns an, was diese Klasse sieht aus wie wirklich , wenn sah mit ildasm:

.field public static initonly valuetype [mscorlib]System.Decimal X
.custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(int8, uint8, uint32, uint32, uint32) = ( 01 00 01 00 00 00 00 00 00 00 00 00 64 00 00 00 00 00 ) 

Lassen Sie mich brechen sie für Sie:

.field public static initonly

entspricht:

public static readonly

Das ist richtig, ein const decimal ist eigentlich ein readonly decimal.

Die eigentliche Behandlung hier ist, dass der Compiler, dass DecimalConstantAttribute verwenden wird seine Magie zu arbeiten.

Nun, dies ist die einzige derartige Magie, die ich von der C # Compiler weiß, aber ich dachte, es wäre erwähnenswert.

Andere Tipps

  

Hat jemand eine Theorie über die Gründe für diese Einschränkung?

Wenn es erlaubt ist nur eine Theorie zu sein, meine Theorie ist, dass const Werte von primitiven Typen können in den MSIL bei wörtlichen Opcode Parameter ausgedrückt werden ... aber die Werte anderer, nicht-primitive Typen kann nicht, weil MSIL ‚doesn t haben die Syntax des Werts eines benutzerdefinierten Typ als Literal auszudrücken.

  

Ich glaube, dass das Konzept der const tatsächlich syntaktischer Zucker in C # ist, und dass es ersetzt nur alle Verwendungen des Namen mit dem wörtlichen Wert

Was macht den Compiler mit const Objekten in anderen Sprachen?

Sie können mit nur lesbar für änderbare Typen, die mich zur Laufzeit ausgewertet werden. Siehe diesem Artikel für die Unterschiede.

consts sind Zahlen und Strings in C # begrenzt, da die Compiler die Variable mit dem wörtlichen Wert im MSIL ersetzt. Mit anderen Worten, wenn Sie schreiben:

const string myName = "Bruce Wayne";
if (someVar == myName)
{
   ...
}

als

tatsächlich behandelt
if (someVar == "Bruce Wayne")
{
   ...
}

und ja, der C # -Compiler ist intelligent genug, um den Gleichheitsoperator (==) auf Strings als

zur Behandlung von
string1.Equals(string2)

Es scheint mir, dass nur Werttypen als Konstante ausgedrückt werden (mit Ausnahme von Strings, die zwischen Wert und Objekttyp irgendwo steht).

Es ist OK für mich. Objekte (Referenzen) auf dem Heap zugewiesen werden, sondern Konstanten sind überhaupt nicht zugeordnet (da sie zum Zeitpunkt der Kompilierung ersetzt sind)

Kurz gesagt, alle einfachen Typen, Aufzählungen und Strings sind unveränderlich, sondern ein Struct zum Beispiel ist es nicht. Sie können eine Struktur mit wandelbarem Zustand haben (Felder, Eigenschaften, auch Referenzen Typen Referenz). So kann der Compiler nicht sicherstellen, dass (bei der Kompilierung), dass der interne Zustand eines Struct Variable kann nicht verändert werden. So muss der Compiler sicher sein, dass eine Art von Definition ist unveränderlich in einem konstanten Ausdruck verwendet werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top