2011-01-04 11 views
30

Sie sind unveränderliche Werttypen auf dem Stapel. Was hält mich davon ab, sie const zu haben?Warum können Strukturen nicht als const deklariert werden?

Referenzen:

+0

Sie können Strukturen const deklarieren. Klassen und Strukturen sind austauschbar und funktionieren für Klassen. – templatetypedef

+1

@templatetypedef: Soll ich "anders als null" erwähnen. – Lazlo

+0

@templatetypedef: Ich bin mir nicht sicher, welche Version von C# Sie verwenden, aber das trifft auf keine Version zu, die ich gesehen habe. – cdhowie

Antwort

35

Da der Wert Typkonstruktor etwas tun könnte - zum Beispiel Logikschalter auf der Basis der Zeit des Tages . Konstante Werttypen sind intellektuell sinnvoll, aber in der Praxis können sie einfach nicht mit benutzerdefinierten Werttypen arbeiten, da die Konstrukteure beliebig viel tun können. (Beachten Sie, dass Konstanten bei Kompilierung ausgewertet werden, des Konstruktor bedeutet hätte bei der Kompilierung ausgeführt werden.)

+0

Danke, werde akzeptiert, wenn S/O mich lässt. Schade, ich habe einen "legitimen" Konstrukteur, wenn ich sagen darf, und ich würde es gerne const haben. Aber naja, ich werde ein anderes Design finden, denke ich. – Lazlo

+2

@Lazlo: Sogar noch, der Compiler müsste es nennen, während es kompiliert wird. Aber der Compiler soll Ihren Code nicht technisch ausführen. – cdhowie

+2

Ich denke, ich suche nach dem Äquivalent von C++ - Aggregat- oder POD-Strukturen: http://en.wikipedia.org/wiki/C%2B%2B_classes Etwas, das nur ein anderer Werttyp oder eine andere Datengruppe ist. Naja. – Lazlo

18

Konst in C# bedeutet, es kann bei der Kompilierung bestimmt werden, weshalb nur sehr primitive Typen wie int und string können ein const sein.

Wenn Sie von einem C-Hintergrund kommen, könnte das Schlüsselwort readonly Ihnen besser passen.

+1

Dies ist die echte Antwort für Programmierer mit C/C++ Hintergrund. – Eonil

+1

@Eonil Nicht 100%; Das C/C++ 'const'-Schlüsselwort dient den Zwecken von Cis 'const' und' readonly' - zum Beispiel führt das Hinzufügen von zwei' readonly int'-Feldern in C# nicht zu einer konstanten Faltung, während zwei 'const int'-Variablen hinzugefügt werden in C/C++ wird (wenn die Werte zur Kompilierzeit bekannt sind). C# 'const "ist näher an dem C++ 11" constexpr "Modifikator, während C#' readonly" kein einziges Analog in C/C++ hat. – cdhowie

+0

@cdhowie, ich denke, das Analog zu 'readonly T'' wo T: struct wäre 'const T &' (in C++). Meist kommt man jedoch zu dem 'readonly' Schlüsselwort in C#, man sucht wirklich nach C++ 's Unterstützung für" const correctness ", die es in C# nicht gibt (und der neue Satz von Immutable classes/pattern versucht a ähnlich, aber ziemlich ungeschickt und arbeitsintensive Alternative). – binki

4

Getestet habe ich nur das readonly Schlüsselwort mit einer einfachen wandelbaren Struktur:

struct Test 
{ 
    public int value; 

    public void setInt(int val) 
    { 
     value = val; 
    } 
} 

static class Program 
{ 
    public static readonly Test t = new Test(); 

    static void Main() 
    { 
     Console.WriteLine(t.value); // Outputs "0" 
     t.setInt(10); 
     //t.value = 10; //Illegal, will not let you assign field of a static struct 
     Console.WriteLine(t.value); // Still outputs "0" 
    } 
} 

Auch wenn ein readonly struct kein Kompilierung konstant Technicly, die Laufzeit läßt es wird nicht ändern. Sogar das Stepping warf die setInt() Methode, die es wie Wertänderungen aussieht, aber die Änderung in Main nicht zeigt.

Ich denke, die Struktur selbst wird in "readonly" Speicher platziert, nicht zulassen, dass sie sich ändern. Im Gegensatz zu einer Klasse, die den Zeiger nur konstant hält, können die Klassenfelder selbst so geändert werden, wie sie es wünschen.

So scheint es static readonly ist effektiv ein const, auch für veränderbare Strukturen.

+4

Alle Instanz-Methoden, -Eigenschaften und -Ereignisse einer Struktur erhalten einen Verweis auf die Struktur, auf der sie arbeiten sollten - das entspricht dem Empfang von 'this' als' Ref'-Parameter - aber für eine lästige Eigenart in vb.net und C# : Wenn eine struct-Methode oder -Eigenschaft in einer schreibgeschützten Strukturinstanz aufgerufen wird, erstellt der Compiler automatisch eine Kopie dieser Instanz und übergibt diese an den betreffenden Code. Dies ergibt eine langsame, aber korrekte Semantik in Fällen, in denen der Code die Struktur nicht ändert, und gebrochene Semantik in Fällen, in denen der Code die Struktur ändert. Ich wünschte, Microsoft würde ein Attribut ... – supercat

+3

... definieren, das struct-Eigenschaften und Methoden erlauben würde, anzugeben, ob sie die übergebene Methode beeinflussen, so dass der Compiler Methoden erlauben könnte, die 'this' nicht modifizieren auf schreibgeschützten Strukturen, verbieten aber die Verwendung von Methoden, die dies tun. Andernfalls ist Ihre beste Wette, die lästige und hässliche Syntax zu akzeptieren: public static void setInt (ref Test it, int val) {it.value = val;} 'und' Test.setInt (ref t, 10); ' was würde richtig quietschen, wenn Sie es auf eine schreibgeschützte Variable "t" versuchten. – supercat

+0

@supercat, also wollen wir wirklich nur, dass MS die Semantik von Cs "const" in C# kopiert :-D – binki

2

Damit der C# -Compiler einen const-Wert eines Strukturtyps erzeugt, muss er wissen, welche Werte in allen Feldern enthalten sein müssen. Der C# -Compiler weiß, wie man die Felder bestimmter Typen wie Decimal initialisiert, aber für die meisten Werttypen hat er keine solchen Kenntnisse.

Es wäre möglich, dass ein Compiler ein Mittel zur Verfügung stellt, um konstante Werte eines Strukturtyps in Kontexten zu deklarieren, in denen alle struct Felder exponiert sind. Wenn die Felder einer Struktur private wären, könnten Konstanten dieses Typs dann nur innerhalb der Struktur deklariert werden; Wenn die Felder internal wären, könnten Konstanten irgendwo in der Assembly deklariert werden; Wenn public, könnten sie überall deklariert werden.

Obwohl ich gerne eine solche Funktion sehen würde, erwarte ich keine gängigen .net-Sprachen, um es zu implementieren. Benannte Konstanten von Typen, die der Compiler inhärent kennt, können an anderen konstanten Ausdrücken teilnehmen, während static readonly Variablen nicht können. Wenn NumRows eine Konstante gleich 4 ist, kann ein Ausdruck wie Arr[3*NumRows+7] durch Arr[19] ersetzt werden, auch wenn NumRows in einer äußeren Baugruppe definiert ist.Dies gibt solchen Konstanten einen wesentlichen Vorteil gegenüber static readonly Variablen. Wenn jedoch eine Konstante von einem Typ ist, den ein Compiler nicht an sich erkennt, hätte sie eine sehr begrenzte Fähigkeit, an irgendwelchen konstanten Ausdrücken teilzunehmen, was effektiv den Vorteil zunichte macht, dass sie überhaupt eine Konstante ist. Wenn eine Werttypkonstante ein exponiertes Feld hätte, wäre es einem Compiler möglich, den Wert dieses Feldes als Konstante zu verwenden, aber da die Ersteller von .net-Sprachen philosophisch gegen Strukturen mit exponierten Feldern sind, würde ich nicht erwarten sie, um eine solche Nutzung zu erlauben, selbst wenn sie es könnten.

Es gibt einige mögliche Anwendungsfälle für die Bevorzugung von Konstanten über static readonly Variablen, aber viele solcher Fälle können mit vorhandenen Typen in akzeptabler Weise behandelt werden. Eine Bibliothek könnte beispielsweise eine const Int64 zur Verfügung stellen, um Informationen über ihre Version zu codieren, und diesen Wert als Standardparameterwert für eine GetLinkedVersionInfo-Methode verwenden. Der fragliche Wert würde beim Kompilieren in den aufrufenden Code "eingebacken" werden, so dass die Methode berichten könnte, mit welcher Version der Bibliothek der Aufrufer verbunden war, und möglicherweise feststellen könnte, ob Kompatibilitätsprobleme mit der Version, die sie ausführt, vorhanden sind.

Verwandte Themen