2012-04-11 7 views
25

Ich frage mich seit einiger Zeit, warum C# const auf Klassen- oder Methodenebene nicht unterstützt. Ich weiß, dass Jon Skeet lange Zeit Unterstützung für Unveränderlichkeit gesucht hat, und ich erkläre, dass die Verwendung der C++ - Syntax der Funktion const dabei helfen könnte. Durch Hinzufügen eines const-Schlüsselworts auf Klassenebene hätten wir volle Unterstützung.Warum unterstützt C# nicht const auf Klassen-/Methodenebene?

Jetzt ist meine Frage, was der Grund dafür ist, dass das C# -Team diese Art von Unterstützung nicht entwickelt hat?

Ich könnte mir vorstellen, dass alles mit einer Kompilierzeitprüfung oder durch Attribute erstellt werden kann, ohne die CLR ändern zu müssen. Es macht mir nichts aus, das const-Verhalten durch Reflexion überschreiben zu können.

Stellen Sie sich vor:

const class NumberContainer 
{ 
    public int Number { get; } 
} 

.. Eine solche Klasse nur Bauzeit bevölkert werden könnte, so würden wir einen Konstruktor müssen in einen int zu nehmen.

Ein weiteres Beispiel ist konst auf einem Verfahren Ebene:

public int AddNumbers(NumberContainer n1, NumberContainer n2) const 
{ 
    return n1.Number + n2.Number; 
} 

Konst-Level-Methoden sollten nicht in der Lage seinen Zustand in ihrer eigenen Klasse oder Instanzen von Referenztypen an sie übergeben zu verändern. Außerdem können Funktionen auf Konst-Ebene nur andere Funktionen auf Const-Ebene aufrufen, solange sie sich in ihrem Gültigkeitsbereich befinden.

Ich bin nicht wirklich sicher, ob lambdas und Delegierte alles zu hart (oder unmöglich) machen würden, aber ich bin mir sicher, dass jemand mit mehr Erfahrung in Sprache und Compiler Design mir sagen könnte.

Als Steve B in den Kommentaren darauf hingewiesen, macht die Existenz von readonly Dinge ein wenig komplexer, als const und readonly sind in der Nähe derselben während runtime, aber readonly Werte können nicht während der Kompilierung Zeit bestimmt werden. Ich denke, wir könnten const und readonly Ebene haben, aber das könnte zu verwirrend sein?

Also, was ist der Grund dafür, dies nicht zu implementieren? Bedenken hinsichtlich der Benutzerfreundlichkeit (das Verständnis von Konstanz in C++ ist normalerweise ziemlich schwierig für neue Benutzer), Sprachdesign (nicht machbar) oder einfach nur Prioritäten (die Zeiten des Unveränderlichkeits-Buzz sind vorbei) ..?

+0

behandelt das Schlüsselwort 'readonly' nicht Ihre Anforderung? –

+0

Oups, mein Schlechter .. Ich hatte auch viele Gedanken über readonly, aber vergessen, es zu posten. Wird meinen Gedankenprozess aktualisieren .. – cwap

+7

Sie fragen im Grunde: "Warum hat die Sprache keine Funktion X" - einfach: entweder wurde sie nicht vorgeschlagen + berücksichtigt + genehmigt + bereich + entworfen + implementiert + getestet + dokumentiert + implementiert (abgewogen gegen andere mögliche Anwendungen für diese Ressource, und die Auswirkungen der Sprache aufgebläht), oder * einige * davon wurde in Betracht gezogen und es wurde als unerwünscht oder verzögert zurückgewiesen. Es ist nicht automatisch, dass jede Sprache jedes vorstellbare Merkmal erhält. –

Antwort

24

Mit einer etwas zirkulären Erklärung, unterstützt C# nicht const, da die CLR keinerlei Unterstützung dafür bietet. Die CLR unterstützt sie nicht, da sie nicht CLS-konform ist.

Es gibt sehr wenige Sprachen, die das Konzept haben. Die C-Sprache hat Unterstützung für const, das in C# von readonly Schlüsselwort gut unterstützt wird. Aber der große Hund ist natürlich C++, der eine viel breitere Anwendbarkeit für const hat, zweifellos die, nach der Sie suchen. Ich werde es vermeiden, festzuhalten, was const bedeuten sollte, das ist ein Wurmloch an sich und nur von "const-ness" zu sprechen, der Eigenschaft, const angewendet zu haben.

Das Problem mit Const-Ness ist, dass es erzwungen werden muss. Das ist ein Problem in C#, wenn eine beliebige andere Sprache eine C# -Klasse verwenden und Const-Ness ignorieren kann, nur weil die Sprache es nicht unterstützt. Es ist natürlich sehr unpraktisch, es auf jede andere CLS-Sprache zu übertragen, nur weil C# es unterstützt.

Durchsetzbarkeit ist ein Problem in C++ auch. Weil die Sprache auch const_cast <> unterstützt. Jeder Client-Code kann die Const-Eigenschaft schnell und unleserlich ablegen. Das darfst du nicht, aber manchmal musst du es auch. Weil es zwei Arten von Konstanz gibt, streng und beobachtbar. In etwa analog zu privater Konstanz und öffentlicher Const. Das veränderbare Schlüsselwort wurde der Sprache später hinzugefügt, um zu versuchen, mit der Notwendigkeit der beobachtbaren Konstanz umzugehen, so dass zumindest die unvermeidliche Verwendung von const_cast <> vermieden werden konnte. Manche Leute sagen, dass C++ eine schwierige Sprache ist. Hör nicht das von C# viel.

+0

nicht. Beste Antwort von allen. Vielen Dank, macht viel Sinn! – cwap

3

Sie sagen, die CLR müssten nicht geändert werden, aber bedenken Sie, dass es keine Standardmethode gibt, diese "Konstante" in kompilierten Assemblies auszudrücken - und dass diese Assemblys sowieso nicht von C# -Code konsumiert werden. Sie können nicht nur für C# tun - Sie müssten es für alle .NET-Sprachen tun.

2

Wie ich glaube der Fall zu sein, bedeutet const verschiedene Dinge in C# im Vergleich zu C++.

In C# können Sie das Schlüsselwort readonly verwenden, um die gewünschte Funktionalität von const zu erhalten.

1

Im Falle Ihres Vorschlags für eine const-Klasse, sagen Sie:

Eine solche Klasse nur Bauzeit bevölkert werden könnte, so würden wir einen Konstruktor müssen in einem int

nehmen

Aber indem Sie alle Eigenschaften trotzdem schreibgeschützt machen, haben Sie bereits erreicht, was Sie gesagt haben.

Ich kann nicht für die C# -Sprache-Designer sprechen, aber vielleicht ist der Grund, const nicht auf viele andere Konstrukte anzuwenden, weil das Hinzufügen einfach nicht der Mühe wert ist und Sie das Problem auf andere Arten umgehen können (wie oben beschrieben) und in anderen Antworten/Kommentaren).

1

Ich kann von Ihrer Frage nicht sagen, wie diese Überlastung des Schlüsselwortes const besonders vorteilhaft wäre.

Ihr erstes Beispiel neu geschrieben rechtlich als

public class NumberContainer 
{ 
    private readonly int number; 

    public NumberContainer(int number) 
    { 
     this.number = number; 
    } 

    public int Number 
    { 
     get { return number; } 
    } 
} 

Vielleicht werden könnte, wenn der Compiler nicht in der Lage ist, die Unveränderlichkeit dieser Klasse zu erkennen (ich weiß nicht), einige Attribute nützlich sein könnten?

In Ihrem zweiten Beispiel verstehe ich nicht, was Sie fahren. Wenn eine Funktion einen konstanten Wert zurückgibt, kann sie durch ein konstantes Feld ersetzt werden.

2

Ich wurde einmal durch die folgende Situation Surpised:

class Vector 
{ 
    private double[] m_data; 
    public int Dimension {get;set;} 

    public double this[int i] 
    { 
     get {return m_data[i];} 
     set {m_data[i] = value;} 
    } 

    public Vector(int n) 
    { 
     this.Dimension = n; 
     this.m_data = new double(n); 
    } 

    public static Vector Zero(int n) 
    { 
     Vector v = new Vector(n); 
     for (int i = 0; i < n; i++) 
     { 
      v[i] = 0.0; 
     } 

     return v; 
    } 

    public static readonly Vector Zero3 = Zero(3); 
} 

Du Vector.Zero3 ist nur lesbar und Sie können es nicht zuordnen, können Sie immer noch seine Komponente zugreifen, und dann wird die folgende dumme Sache passiert:

Vector a = Vector.Zero3; 
a[0]  = 2.87; 

und jetzt, da ein ist nichts anderes als ein Hinweis auf Vector.Vector3 letztere auch Vector.Vector3 [0] == 2,87 hat!

Nachdem ich einmal in diese Grube gefallen bin, erfand ich einen sehr einfachen Hack, der zwar nicht elegant ist, aber seine Funktion erfüllt.

nämlich in eine Klasse, die ich nehme an statischen Nur-Lese „Konstanten“ zu erzeugen, führe ich eine Boolesche Flagge:

class Vector 
{ 
    private double[] m_data; 
    public int Dimension {get;set;} 
    private bool m_bIsConstant = false; 
    ... 

    public double this[int i] 
    { 
     get {return m_data[i];} 
     set 
     { 
      if (!m_bIsConstant) 
      { 
       m_data[i] = value; 
      } 
     } 
    } 
    ... 
    public static Vector Zero(int n) 
    { 
     Vector v = new Vector(n); 
     for (int i = 0; i < n; i++) 
     { 
      v[i] = 0.0; 
     } 

     v.m_bIsConstant = true; 
     return v; 
    } 
    ... 
} 

Dieser Hack garantiert, dass Ihre statische nur lesbare Variable wird nie geändert werden.

Verwandte Themen