Der Grund ist, dass const nur auf ein Feld angewendet werden kann, dessen Wert zur Kompilierungszeit bekannt ist. Der angezeigte Array-Initialisierer ist kein konstanter Ausdruck in C #, daher wird ein Compilerfehler erzeugt.
Das Deklarieren readonlylöst dieses Problem, da der Wert erst zur Laufzeit initialisiert wird (obwohl er garantiert vor der ersten Verwendung des Arrays initialisiert wurde).
Je nachdem, was Sie letztendlich erreichen möchten, können Sie auch eine Aufzählung deklarieren:
Beachten Sie, dass das Array hier natürlich nicht schreibgeschützt ist. Titel [2] = "Walisisch"; würde zur Laufzeit gut
funktionieren
46
Sie wollen es wahrscheinlich auch statisch
Tymtam
4
Wie wäre es, ein "const" -Array in einem Methodenkörper zu deklarieren, nicht in der Klasse eins?
Serhio
19
Entschuldigung für die Abstimmung, aber const impliziert auch statische Aufladung. Das Deklarieren des Arrays als schreibgeschützt kommt einer Problemumgehung nicht nahe. Es muss readonly staticÄhnlichkeit mit der angeforderten Semantik haben.
Anton
3
@Anton, haben Sie und Ihre "Follower" die Downvote entfernt? Für mich staticist es nicht erforderlich, damit es funktioniert. Es wird lediglich die Möglichkeit hinzugefügt, Titlesohne Instanz zu referenzieren , aber die Möglichkeit zu entfernen, den Wert für verschiedene Instanzen zu ändern (z. B. können Sie einen Konstruktor mit Parametern haben, je nachdem, welchen Wert Sie für dieses readonlyFeld ändern ).
Sinatr
57
Sie können das Array als deklarieren readonly, aber denken Sie daran, dass Sie das Element des readonlyArrays ändern können .
In .NET 4.5 und höher können Sie eine Liste als IReadOnlyList <string> anstelle von IList <string> deklarieren.
Grzegorz Smulko
Um es klar zu machen, können Sie die Werte in einer IReadOnlyList trotzdem ändern (nur keine Elemente hinzufügen oder entfernen). Aber ja, es wäre besser als eine IList, es als IReadOnlyList zu deklarieren.
KevinVictor
Die Frage ist über constNICHT readonly...
Yousha Aleayoub
51
Sie können kein 'const'-Array erstellen, da Arrays Objekte sind und nur zur Laufzeit erstellt werden können und const-Entitäten zur Kompilierungszeit aufgelöst werden.
Sie können stattdessen Ihr Array als "schreibgeschützt" deklarieren. Dies hat den gleichen Effekt wie const, außer dass der Wert zur Laufzeit festgelegt werden kann. Es kann nur einmal eingestellt werden und ist danach ein schreibgeschützter (dh konstanter) Wert.
Dieser Beitrag hebt hervor, warum Arrays nicht als Konstanten deklariert werden können
Radderz
1
Es ist möglich, ein konstantes Array zu deklarieren. Das Problem besteht darin, es mit einem konstanten Wert zu initialisieren. Das einzige funktionierende Beispiel, das mir in den Sinn kommt, ist const int[] a = null;das nicht sehr nützliche, aber tatsächlich eine Instanz einer Array-Konstante.
Dadurch wird eine schreibgeschützte statische Eigenschaft erstellt, Sie können jedoch weiterhin den Inhalt des zurückgegebenen Arrays ändern. Wenn Sie die Eigenschaft jedoch erneut aufrufen, erhalten Sie das ursprüngliche, unveränderte Array erneut.
Zur Verdeutlichung ist dieser Code derselbe wie (oder eigentlich eine Abkürzung für):
Bitte beachten Sie, dass dieser Ansatz einen Nachteil hat: Bei jeder Referenz wird tatsächlich ein neues Array instanziiert. Wenn Sie also ein sehr großes Array verwenden, ist dies möglicherweise nicht die effizienteste Lösung. Wenn Sie jedoch dasselbe Array erneut verwenden (indem Sie es beispielsweise in ein privates Attribut einfügen), wird erneut die Möglichkeit eröffnet, den Inhalt des Arrays zu ändern.
Wenn Sie ein unveränderliches Array (oder eine Liste) haben möchten, können Sie auch Folgendes verwenden:
Was ist in diesem Fall der Gewinn der Nutzung von Immobilien anstelle von Feldern?
nicolay.anykienko
2
Ein Feld kann nicht bei jedem Aufruf ein neues Objekt zurückgeben. Eine Eigenschaft ist im Grunde eine Art "Funktion in Verkleidung".
Mjepson
1
Wenn Sie sich auf die letzte Option bezogen haben, kann dies sowohl über ein Feld als auch über eine Eigenschaft erfolgen. Da diese jedoch öffentlich ist, bevorzuge ich eine Eigenschaft. Ich benutze seit Einführung von Properties kein öffentliches Feld mehr.
Mjepson
1
Der erste Ansatz hat noch einen weiteren Nachteil: Sie erhalten keinen Kompilierungsfehler, wenn Sie beispielsweise zuweisen. Titles[0]Tatsächlich wird der Zuweisungsversuch stillschweigend ignoriert. In Kombination mit der Ineffizienz, das Array jedes Mal neu zu erstellen, frage ich mich, ob dieser Ansatz überhaupt eine Darstellung wert ist. Im Gegensatz dazu ist der zweite Ansatz effizient und Sie müssen alles tun, um die Unveränderlichkeit zu besiegen.
mklement0
6
Wenn Sie ein Array hinter einer IReadOnlyList-Schnittstelle deklarieren, erhalten Sie ein konstantes Array mit konstanten Werten, das zur Laufzeit deklariert wird:
using System.Collections.ObjectModel;// ...publicReadOnlyCollection<string>Titles{get;}=newReadOnlyCollection<string>(newstring[]{"German","Spanish","Corrects","Wrongs"});
Hinweis: Da die Sammlung konzeptionell konstant ist, kann es sinnvoll sein static, sie in der Klasse zu deklarieren .
Obenstehendes:
Initialisiert das implizite Sicherungsfeld der Eigenschaft einmal mit dem Array.
Beachten Sie, dass { get; }- das heißt, erklärt nur eine Eigenschaft Getter - ist das, was die Eigenschaft macht sich implizit nur schreib (versucht zu kombinieren readonlymit { get; }ist eigentlich ein Syntaxfehler).
Alternativ können Sie das Feld weglassen { get; }und hinzufügen readonly, um ein Feld anstelle einer Eigenschaft zu erstellen , wie in der Frage beschrieben. Es ist jedoch eine gute Angewohnheit , öffentliche Datenelemente als Eigenschaften und nicht als Felder bereitzustellen.
Erstellt eine Array- ähnliche Struktur (die einen indizierten Zugriff ermöglicht ), die wirklich und robust schreibgeschützt ist (konzeptionell konstant, sobald sie erstellt wurde), sowohl in Bezug auf:
Verhindern der Änderung der gesamten Sammlung (z. B. durch Entfernen oder Hinzufügen von Elementen oder durch Zuweisen einer neuen Sammlung zur Variablen).
Verhinderung der Veränderung einzelner Elemente .
(Auch indirekte Änderung nicht möglich ist - im Gegensatz zu einer IReadOnlyList<T>Lösung, bei der ein (string[])Guss verwendet werden kann , Schreibzugriff auf die Elemente zu gewinnen , wie es in gezeigt mjepsen die hilfreiche Antwort .
Die gleiche Verwundbarkeit gilt für die IReadOnlyCollection<T>Schnittstelle , die trotz der Namensähnlichkeit zu KlasseReadOnlyCollection , nicht unterstützt sogar indexierten Zugang , es grundsätzlich nicht geeignet für die Bereitstellung von Array-ähnlichem Zugriff zu machen.)
@mortb: IReadOnlyCollectionUnterstützt leider keinen indizierten Zugriff, daher kann er hier nicht verwendet werden. Darüber hinaus ist es wie IReadOnlyList(das über einen indizierten Zugriff verfügt) anfällig für Elementmanipulationen durch Zurücksetzen auf string[]. Mit anderen Worten: ReadOnlyCollection(in die Sie kein String-Array umwandeln können) ist die robusteste Lösung. Es ist eine Option, keinen Getter zu verwenden (und ich habe die Antwort aktualisiert, um dies zu beachten), aber bei öffentlichen Daten ist es wahrscheinlich besser, bei einer Eigenschaft zu bleiben.
mklement0
5
Für meine Bedürfnisse definiere ich staticArray, anstatt unmöglich constund es funktioniert:
public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
Das einfache Entfernen constaus dem OP-Beispiel funktioniert auch, aber das (oder Ihre Antwort) ermöglicht es, sowohl die TitlesInstanz als auch einen beliebigen Wert zu ändern . Worum geht es in dieser Antwort?
Sinatr
@ Sinatr, ich habe dies vor 3 Jahren beantwortet, als ich in C # gearbeitet habe. Ich habe es verlassen, jetzt bin ich in der Java-Welt. Vielleicht habe ich vergessen hinzuzufügenreadonly
ALZ
Nach reiflicher Überlegung ist die Antwort eine direkte , wie OP - Code Arbeits machen , ohne const/ readonlyÜberlegungen, einfach machen es funktioniert (wie wenn constwar ein Syntaxfehler). Für manche Menschen scheint es eine wertvolle Antwort zu sein (vielleicht haben sie auch versucht, sie versehentlich zu verwenden const?).
Sinatr
5
Sie können einen anderen Ansatz wählen: Definieren Sie eine konstante Zeichenfolge, um Ihr Array darzustellen, und teilen Sie die Zeichenfolge dann bei Bedarf in ein Array auf, z
Ich denke, die Kosten für die Durchführung des Split übersteigen bei weitem alle Vorteile, die durch die Definition von const erzielt werden. Aber +1 für einen einzigartigen Ansatz und Denken über den Tellerrand hinaus! ;)
Radderz
Ich wollte die gleiche Lösung veröffentlichen und sah dann, dass dies entgegen den harten und negativen Bemerkungen tatsächlich perfekt für mein Szenario war, in dem ich eine Konstante an ein Attribut übergeben musste und dann den Wert im Attributkonstruktor aufteilte Holen Sie sich, was ich brauchte. und ich sehe keinen Grund, warum es Leistungskosten verursachen wird, da Attribute nicht für jede Instanz erstellt werden.
Kalpesh Popat
4
Der Vollständigkeit halber verfügen wir jetzt auch über ImmutableArrays. Dies sollte wirklich unveränderlich sein:
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;publicReadOnlyCollection<string>Titles{get{returnnewList<string>{"German","Spanish","Corrects","Wrongs"}.AsReadOnly();}}
Es ist sehr ähnlich zu einem schreibgeschützten Array.
Sie können das einfach so machen public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();; Sie müssen die Liste nicht bei jedem Abruf neu erstellen, wenn Sie sie trotzdem zu einer ReadOnlyCollection machen.
Nyerguds
3
Dies ist die einzig richtige Antwort. Sie können dies derzeit nicht tun.
Alle anderen Antworten schlagen vor, statische schreibgeschützte Variablen zu verwenden, die ähnlich sind , die einer Konstanten , aber nicht identisch sind. Eine Konstante ist in der Baugruppe fest codiert. Eine statische schreibgeschützte Variable kann einmal eingestellt werden, wahrscheinlich wenn ein Objekt initialisiert wird.
Diese sind manchmal austauschbar, aber nicht immer.
Arrays sind wahrscheinlich eines der Dinge, die nur zur Laufzeit ausgewertet werden können. Konstanten müssen zur Kompilierungszeit ausgewertet werden. Versuchen Sie, "readonly" anstelle von "const" zu verwenden.
Alternativ können Sie stattdessen eine statische Eigenschaft verwenden, um das Problem zu umgehen, dass Elemente mit einem schreibgeschützten Array geändert werden können. (Die einzelnen Elemente können weiterhin geändert werden, diese Änderungen werden jedoch nur auf der lokalen Kopie des Arrays vorgenommen.)
Antworten:
Ja, aber Sie müssen es deklarieren
readonly
anstattconst
:Der Grund ist, dass
const
nur auf ein Feld angewendet werden kann, dessen Wert zur Kompilierungszeit bekannt ist. Der angezeigte Array-Initialisierer ist kein konstanter Ausdruck in C #, daher wird ein Compilerfehler erzeugt.Das Deklarieren
readonly
löst dieses Problem, da der Wert erst zur Laufzeit initialisiert wird (obwohl er garantiert vor der ersten Verwendung des Arrays initialisiert wurde).Je nachdem, was Sie letztendlich erreichen möchten, können Sie auch eine Aufzählung deklarieren:
quelle
readonly static
Ähnlichkeit mit der angeforderten Semantik haben.static
ist es nicht erforderlich, damit es funktioniert. Es wird lediglich die Möglichkeit hinzugefügt,Titles
ohne Instanz zu referenzieren , aber die Möglichkeit zu entfernen, den Wert für verschiedene Instanzen zu ändern (z. B. können Sie einen Konstruktor mit Parametern haben, je nachdem, welchen Wert Sie für diesesreadonly
Feld ändern ).Sie können das Array als deklarieren
readonly
, aber denken Sie daran, dass Sie das Element desreadonly
Arrays ändern können .Erwägen Sie die Verwendung von enum, wie Cody vorgeschlagen hat, oder IList.
quelle
const
NICHTreadonly
...Sie können kein 'const'-Array erstellen, da Arrays Objekte sind und nur zur Laufzeit erstellt werden können und const-Entitäten zur Kompilierungszeit aufgelöst werden.
Sie können stattdessen Ihr Array als "schreibgeschützt" deklarieren. Dies hat den gleichen Effekt wie const, außer dass der Wert zur Laufzeit festgelegt werden kann. Es kann nur einmal eingestellt werden und ist danach ein schreibgeschützter (dh konstanter) Wert.
quelle
const int[] a = null;
das nicht sehr nützliche, aber tatsächlich eine Instanz einer Array-Konstante.Seit C # 6 können Sie es wie folgt schreiben:
Siehe auch: C #: Das neue und verbesserte C # 6.0 (insbesondere das Kapitel "Funktionen und Eigenschaften des Ausdrucks")
Dadurch wird eine schreibgeschützte statische Eigenschaft erstellt, Sie können jedoch weiterhin den Inhalt des zurückgegebenen Arrays ändern. Wenn Sie die Eigenschaft jedoch erneut aufrufen, erhalten Sie das ursprüngliche, unveränderte Array erneut.
Zur Verdeutlichung ist dieser Code derselbe wie (oder eigentlich eine Abkürzung für):
Bitte beachten Sie, dass dieser Ansatz einen Nachteil hat: Bei jeder Referenz wird tatsächlich ein neues Array instanziiert. Wenn Sie also ein sehr großes Array verwenden, ist dies möglicherweise nicht die effizienteste Lösung. Wenn Sie jedoch dasselbe Array erneut verwenden (indem Sie es beispielsweise in ein privates Attribut einfügen), wird erneut die Möglichkeit eröffnet, den Inhalt des Arrays zu ändern.
Wenn Sie ein unveränderliches Array (oder eine Liste) haben möchten, können Sie auch Folgendes verwenden:
Dies birgt jedoch immer noch das Risiko von Änderungen, da Sie es immer noch in einen String [] umwandeln und den Inhalt als solchen ändern können:
quelle
Titles[0]
Tatsächlich wird der Zuweisungsversuch stillschweigend ignoriert. In Kombination mit der Ineffizienz, das Array jedes Mal neu zu erstellen, frage ich mich, ob dieser Ansatz überhaupt eine Darstellung wert ist. Im Gegensatz dazu ist der zweite Ansatz effizient und Sie müssen alles tun, um die Unveränderlichkeit zu besiegen.Wenn Sie ein Array hinter einer IReadOnlyList-Schnittstelle deklarieren, erhalten Sie ein konstantes Array mit konstanten Werten, das zur Laufzeit deklariert wird:
Verfügbar in .NET 4.5 und höher.
quelle
Eine .NET Framework v4.5 + -Lösung , die die Antwort von tdbeckett verbessert :
Hinweis: Da die Sammlung konzeptionell konstant ist, kann es sinnvoll sein
static
, sie in der Klasse zu deklarieren .Obenstehendes:
Initialisiert das implizite Sicherungsfeld der Eigenschaft einmal mit dem Array.
Beachten Sie, dass
{ get; }
- das heißt, erklärt nur eine Eigenschaft Getter - ist das, was die Eigenschaft macht sich implizit nur schreib (versucht zu kombinierenreadonly
mit{ get; }
ist eigentlich ein Syntaxfehler).Alternativ können Sie das Feld weglassen
{ get; }
und hinzufügenreadonly
, um ein Feld anstelle einer Eigenschaft zu erstellen , wie in der Frage beschrieben. Es ist jedoch eine gute Angewohnheit , öffentliche Datenelemente als Eigenschaften und nicht als Felder bereitzustellen.Erstellt eine Array- ähnliche Struktur (die einen indizierten Zugriff ermöglicht ), die wirklich und robust schreibgeschützt ist (konzeptionell konstant, sobald sie erstellt wurde), sowohl in Bezug auf:
(Auch indirekte Änderung nicht möglich ist - im Gegensatz zu einer
IReadOnlyList<T>
Lösung, bei der ein(string[])
Guss verwendet werden kann , Schreibzugriff auf die Elemente zu gewinnen , wie es in gezeigt mjepsen die hilfreiche Antwort .Die gleiche Verwundbarkeit gilt für die
IReadOnlyCollection<T>
Schnittstelle , die trotz der Namensähnlichkeit zu KlasseReadOnlyCollection
, nicht unterstützt sogar indexierten Zugang , es grundsätzlich nicht geeignet für die Bereitstellung von Array-ähnlichem Zugriff zu machen.)quelle
IReadOnlyCollection
Unterstützt leider keinen indizierten Zugriff, daher kann er hier nicht verwendet werden. Darüber hinaus ist es wieIReadOnlyList
(das über einen indizierten Zugriff verfügt) anfällig für Elementmanipulationen durch Zurücksetzen aufstring[]
. Mit anderen Worten:ReadOnlyCollection
(in die Sie kein String-Array umwandeln können) ist die robusteste Lösung. Es ist eine Option, keinen Getter zu verwenden (und ich habe die Antwort aktualisiert, um dies zu beachten), aber bei öffentlichen Daten ist es wahrscheinlich besser, bei einer Eigenschaft zu bleiben.Für meine Bedürfnisse definiere ich
static
Array, anstatt unmöglichconst
und es funktioniert:public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
quelle
const
aus dem OP-Beispiel funktioniert auch, aber das (oder Ihre Antwort) ermöglicht es, sowohl dieTitles
Instanz als auch einen beliebigen Wert zu ändern . Worum geht es in dieser Antwort?readonly
const
/readonly
Überlegungen, einfach machen es funktioniert (wie wennconst
war ein Syntaxfehler). Für manche Menschen scheint es eine wertvolle Antwort zu sein (vielleicht haben sie auch versucht, sie versehentlich zu verwendenconst
?).Sie können einen anderen Ansatz wählen: Definieren Sie eine konstante Zeichenfolge, um Ihr Array darzustellen, und teilen Sie die Zeichenfolge dann bei Bedarf in ein Array auf, z
Mit diesem Ansatz erhalten Sie eine Konstante, die in der Konfiguration gespeichert und bei Bedarf in ein Array konvertiert werden kann.
quelle
Der Vollständigkeit halber verfügen wir jetzt auch über ImmutableArrays. Dies sollte wirklich unveränderlich sein:
Benötigt System.Collections.Immutable NuGet-Referenz
https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx
quelle
So können Sie tun, was Sie wollen:
Es ist sehr ähnlich zu einem schreibgeschützten Array.
quelle
public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
; Sie müssen die Liste nicht bei jedem Abruf neu erstellen, wenn Sie sie trotzdem zu einer ReadOnlyCollection machen.Dies ist die einzig richtige Antwort. Sie können dies derzeit nicht tun.
Alle anderen Antworten schlagen vor, statische schreibgeschützte Variablen zu verwenden, die ähnlich sind , die einer Konstanten , aber nicht identisch sind. Eine Konstante ist in der Baugruppe fest codiert. Eine statische schreibgeschützte Variable kann einmal eingestellt werden, wahrscheinlich wenn ein Objekt initialisiert wird.
Diese sind manchmal austauschbar, aber nicht immer.
quelle
Ich glaube, Sie können es nur schreibgeschützt machen.
quelle
Arrays sind wahrscheinlich eines der Dinge, die nur zur Laufzeit ausgewertet werden können. Konstanten müssen zur Kompilierungszeit ausgewertet werden. Versuchen Sie, "readonly" anstelle von "const" zu verwenden.
quelle
Alternativ können Sie stattdessen eine statische Eigenschaft verwenden, um das Problem zu umgehen, dass Elemente mit einem schreibgeschützten Array geändert werden können. (Die einzelnen Elemente können weiterhin geändert werden, diese Änderungen werden jedoch nur auf der lokalen Kopie des Arrays vorgenommen.)
Dies ist natürlich nicht besonders effizient, da jedes Mal ein neues String-Array erstellt wird.
quelle
Beste Alternative:
quelle