La razón es que const solo se puede aplicar a un campo cuyo valor se conoce en tiempo de compilación. El inicializador de matriz que ha mostrado no es una expresión constante en C #, por lo que produce un error de compilación.
Declarar que readonlyresuelve ese problema porque el valor no se inicializa hasta el tiempo de ejecución (aunque se garantiza que se ha inicializado antes de la primera vez que se usa la matriz).
Dependiendo de qué es lo que finalmente desea lograr, también puede considerar declarar una enumeración:
Tenga en cuenta que la matriz aquí no es de solo lectura, por supuesto; Títulos [2] = "Galés"; funcionaría bien en tiempo de ejecución
Marc Gravell
46
Probablemente también lo quieras estático
tymtam
44
¿qué tal declarar una matriz "const" en un cuerpo de método, no en la clase uno?
serhio
19
Perdón por el voto negativo, pero const también implica estática. Declarar la matriz como solo lectura no está cerca de una solución alternativa. tiene que ser readonly staticpara tener algún parecido con la semántica solicitada.
Anton
3
@Anton, ¿usted y sus "seguidores" han eliminado el voto negativo? Para mí, staticno es necesario que funcione, solo agrega la posibilidad de hacer referencia Titlessin tener una instancia, pero elimina la posibilidad de cambiar el valor para diferentes instancias (por ejemplo, puede tener un constructor con un parámetro dependiendo de cuál cambie el valor de ese readonlycampo).
Sinatr
57
Puede declarar la matriz como readonly, pero tenga en cuenta que puede cambiar el elemento de la readonlymatriz.
En .NET 4.5 y superior puede declarar una lista como IReadOnlyList <string> en lugar de IList <string>.
Grzegorz Smulko
Para que quede claro, aún puede cambiar los valores en una IReadOnlyList (simplemente no agregar o eliminar elementos). Pero sí, declararlo como una IReadOnlyList sería mejor que una IList.
KevinVictor
La pregunta es sobre constNO readonly...
Yousha Aleayoub
51
No puede crear una matriz 'const' porque las matrices son objetos y solo se pueden crear en tiempo de ejecución y las entidades const se resuelven en tiempo de compilación.
Lo que puede hacer en su lugar es declarar su matriz como "solo lectura". Esto tiene el mismo efecto que const, excepto que el valor se puede establecer en tiempo de ejecución. Solo se puede configurar una vez y luego es un valor de solo lectura (es decir, constante).
Esta publicación destaca por qué las matrices no pueden declararse como constantes
Radderz
1
Es posible declarar una matriz constante; El problema es inicializarlo con un valor constante. El único ejemplo de trabajo que viene a la mente es el const int[] a = null;que no es muy útil, pero sí una instancia de una constante de matriz.
Esto creará una propiedad estática de solo lectura, pero aún así le permitirá alterar el contenido de la matriz devuelta, pero cuando vuelva a llamar a la propiedad, volverá a obtener la matriz original sin alterar.
Para aclarar, este código es el mismo que (o en realidad es una abreviatura de):
Tenga en cuenta que este enfoque tiene un inconveniente: en realidad, se crea una nueva matriz en todas y cada una de las referencias, por lo que si está utilizando una matriz muy grande, esta podría no ser la solución más eficiente. Pero si reutiliza la misma matriz (poniéndola en un atributo privado, por ejemplo), volverá a abrir la posibilidad de cambiar el contenido de la matriz.
Si desea tener una matriz (o lista) inmutable, también puede usar:
¿Cuál es el beneficio de usar la propiedad en lugar del campo en este caso?
nicolay.anykienko
2
Un campo no puede devolver un nuevo objeto en cada llamada. Una propiedad es básicamente una especie de "función disfrazada".
mjepson
1
Si se refería a la última opción, eso se puede hacer utilizando un campo o una propiedad, pero como es público, prefiero una Propiedad. Nunca uso un campo público desde la introducción de Propiedades.
mjepson
1
Hay otro inconveniente en el primer enfoque: no obtendrá un error de compilación si asigna Titles[0], por ejemplo, en efecto, el intento de asignación se ignora silenciosamente. Combinado con la ineficiencia de recrear la matriz cada vez, me pregunto si vale la pena mostrar este enfoque. Por el contrario, el segundo enfoque es eficiente, y tienes que salir de tu camino para vencer la inmutabilidad.
mklement0
6
Si declara una matriz detrás de una interfaz IReadOnlyList, obtiene una matriz constante con valores constantes que se declara en tiempo de ejecución:
using System.Collections.ObjectModel;// ...publicReadOnlyCollection<string>Titles{get;}=newReadOnlyCollection<string>(newstring[]{"German","Spanish","Corrects","Wrongs"});
Nota: Dado que la colección es conceptualmente constante, puede tener sentido staticdeclararla a nivel de clase .
Lo anterior:
Inicializa el campo de respaldo implícito de la propiedad una vez con la matriz.
Tenga en cuenta que { get; }- es decir, declarar solamente una propiedad getter - es lo que hace que la propiedad en sí implícitamente sólo lectura (tratando de combinar readonlycon la { get; }realidad, es un error de sintaxis).
Alternativamente, puede omitir { get; }y agregar readonlypara crear un campo en lugar de una propiedad, como en la pregunta, pero exponer a los miembros de datos públicos como propiedades en lugar de campos es un buen hábito para formar.
Crea una estructura de tipo matriz (que permite el acceso indexado ) que es verdadera y robustamente de solo lectura (conceptualmente constante, una vez creada), ambos con respecto a:
evitar la modificación de la colección en su conjunto (como eliminar o agregar elementos o asignar una nueva colección a la variable).
evitando la modificación de elementos individuales .
(Incluso la modificación indirecta no es posible, a diferencia de una IReadOnlyList<T>solución, donde un (string[])reparto se puede utilizar para obtener acceso de escritura a los elementos , como se muestra en la útil respuesta de mjepsen .
La misma vulnerabilidad se aplica a la IReadOnlyCollection<T>interfaz , que, a pesar de la similitud en el nombre a la claseReadOnlyCollection , ni siquiera admite el acceso indexado , lo que lo hace fundamentalmente inadecuado para proporcionar acceso tipo matriz).
@mortb: Desafortunadamente, IReadOnlyCollectionno admite acceso indexado, por lo que no se puede usar aquí. Además, like IReadOnlyList(que tiene acceso indexado) es susceptible a la manipulación de elementos al volver a enviarlos string[]. En otras palabras: ReadOnlyCollection(a la que no puede convertir una matriz de cadenas) es la solución más sólida. No usar un captador es una opción (y he actualizado la respuesta para tener en cuenta eso), pero con los datos públicos probablemente sea mejor quedarse con una propiedad.
mklement0
5
Para mis necesidades defino staticmatriz, en lugar de imposible consty funciona:
public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
Simplemente eliminar constdel ejemplo OP también funciona, pero eso (o su respuesta) permite cambiar tanto: Titlesinstancia como cualquier valor. Entonces, ¿cuál es el punto en esta respuesta?
Sinatr
@Sinatr, respondí esto hace 3 años, cuando comencé a trabajar en C #. Lo dejé, ahora estoy en el mundo de Java. Tal vez olvidé agregarreadonly
ALZ
Después de pensarlo dos veces, su respuesta es una forma directa de hacer que el código OP funcione , sin ninguna const/ readonlyconsideración, simplemente haciéndolo funcionar (como si constfuera un error de sintaxis). Para algunas personas, parece ser una respuesta valiosa (¿tal vez también intentaron usarla constpor error?).
Sinatr
5
Podría adoptar un enfoque diferente: defina una cadena constante para representar su matriz y luego divida la cadena en una matriz cuando la necesite, p. Ej.
Creo que el costo de realizar la división supera con creces cualquier beneficio obtenido al definir const. ¡Pero +1 para un enfoque único y pensar fuera de la caja! ;)
Radderz
Estaba a punto de publicar la misma solución y luego vi esto, al contrario de los comentarios duros y negativos, esto era realmente perfecto para mi escenario, donde necesitaba pasar una constante a un Atributo, y luego dividí el valor en el constructor de atributos para Conseguí lo que necesitaba. y no veo ninguna razón por la que tendrá un costo de rendimiento ya que no se crean atributos para cada instancia.
Kalpesh Popat
4
En aras de la exhaustividad, ahora también tenemos ImmutableArrays a nuestra disposición. Esto debería ser realmente inmutable:
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;publicReadOnlyCollection<string>Titles{get{returnnewList<string>{"German","Spanish","Corrects","Wrongs"}.AsReadOnly();}}
Es muy similar a hacer una matriz de solo lectura.
Puedes hacer eso como public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();; no es necesario volver a crear la lista en cada recuperación si la convierte en una ReadOnlyCollection de todos modos.
Nyerguds
3
Esta es la única respuesta correcta. Actualmente no puedes hacer esto.
Todas las otras respuestas sugieren usar variables estáticas de solo lectura que son similares , pero no iguales a una constante. Una constante está codificada en el ensamblaje. Una variable de solo lectura estática se puede configurar una vez, probablemente a medida que se inicializa un objeto.
Estos a veces son intercambiables, pero no siempre.
Las matrices son probablemente una de esas cosas que solo se pueden evaluar en tiempo de ejecución. Las constantes deben evaluarse en tiempo de compilación. Intente usar "readonly" en lugar de "const".
Como alternativa, para solucionar el problema de elementos que se pueden modificar con una matriz de solo lectura, puede usar una propiedad estática en su lugar. (Los elementos individuales aún se pueden cambiar, pero estos cambios solo se realizarán en la copia local de la matriz).
Respuestas:
Sí, pero debe declararlo en
readonly
lugar deconst
:La razón es que
const
solo se puede aplicar a un campo cuyo valor se conoce en tiempo de compilación. El inicializador de matriz que ha mostrado no es una expresión constante en C #, por lo que produce un error de compilación.Declarar que
readonly
resuelve ese problema porque el valor no se inicializa hasta el tiempo de ejecución (aunque se garantiza que se ha inicializado antes de la primera vez que se usa la matriz).Dependiendo de qué es lo que finalmente desea lograr, también puede considerar declarar una enumeración:
fuente
readonly static
para tener algún parecido con la semántica solicitada.static
no es necesario que funcione, solo agrega la posibilidad de hacer referenciaTitles
sin tener una instancia, pero elimina la posibilidad de cambiar el valor para diferentes instancias (por ejemplo, puede tener un constructor con un parámetro dependiendo de cuál cambie el valor de esereadonly
campo).Puede declarar la matriz como
readonly
, pero tenga en cuenta que puede cambiar el elemento de lareadonly
matriz.Considere usar enum, como sugirió Cody, o IList.
fuente
const
NOreadonly
...No puede crear una matriz 'const' porque las matrices son objetos y solo se pueden crear en tiempo de ejecución y las entidades const se resuelven en tiempo de compilación.
Lo que puede hacer en su lugar es declarar su matriz como "solo lectura". Esto tiene el mismo efecto que const, excepto que el valor se puede establecer en tiempo de ejecución. Solo se puede configurar una vez y luego es un valor de solo lectura (es decir, constante).
fuente
const int[] a = null;
que no es muy útil, pero sí una instancia de una constante de matriz.Desde C # 6 puedes escribirlo como:
Ver también: C #: El nuevo y mejorado C # 6.0 (específicamente el capítulo "Funciones y propiedades con cuerpo de expresión")
Esto creará una propiedad estática de solo lectura, pero aún así le permitirá alterar el contenido de la matriz devuelta, pero cuando vuelva a llamar a la propiedad, volverá a obtener la matriz original sin alterar.
Para aclarar, este código es el mismo que (o en realidad es una abreviatura de):
Tenga en cuenta que este enfoque tiene un inconveniente: en realidad, se crea una nueva matriz en todas y cada una de las referencias, por lo que si está utilizando una matriz muy grande, esta podría no ser la solución más eficiente. Pero si reutiliza la misma matriz (poniéndola en un atributo privado, por ejemplo), volverá a abrir la posibilidad de cambiar el contenido de la matriz.
Si desea tener una matriz (o lista) inmutable, también puede usar:
Pero, esto todavía tiene el riesgo de cambios, ya que aún puede volver a convertirlo en una cadena [] y alterar el contenido, como tal:
fuente
Titles[0]
, por ejemplo, en efecto, el intento de asignación se ignora silenciosamente. Combinado con la ineficiencia de recrear la matriz cada vez, me pregunto si vale la pena mostrar este enfoque. Por el contrario, el segundo enfoque es eficiente, y tienes que salir de tu camino para vencer la inmutabilidad.Si declara una matriz detrás de una interfaz IReadOnlyList, obtiene una matriz constante con valores constantes que se declara en tiempo de ejecución:
Disponible en .NET 4.5 y superior.
fuente
Una solución .NET Framework v4.5 + que mejora la respuesta de tdbeckett :
Nota: Dado que la colección es conceptualmente constante, puede tener sentido
static
declararla a nivel de clase .Lo anterior:
Inicializa el campo de respaldo implícito de la propiedad una vez con la matriz.
Tenga en cuenta que
{ get; }
- es decir, declarar solamente una propiedad getter - es lo que hace que la propiedad en sí implícitamente sólo lectura (tratando de combinarreadonly
con la{ get; }
realidad, es un error de sintaxis).Alternativamente, puede omitir
{ get; }
y agregarreadonly
para crear un campo en lugar de una propiedad, como en la pregunta, pero exponer a los miembros de datos públicos como propiedades en lugar de campos es un buen hábito para formar.Crea una estructura de tipo matriz (que permite el acceso indexado ) que es verdadera y robustamente de solo lectura (conceptualmente constante, una vez creada), ambos con respecto a:
(Incluso la modificación indirecta no es posible, a diferencia de una
IReadOnlyList<T>
solución, donde un(string[])
reparto se puede utilizar para obtener acceso de escritura a los elementos , como se muestra en la útil respuesta de mjepsen .La misma vulnerabilidad se aplica a la
IReadOnlyCollection<T>
interfaz , que, a pesar de la similitud en el nombre a la claseReadOnlyCollection
, ni siquiera admite el acceso indexado , lo que lo hace fundamentalmente inadecuado para proporcionar acceso tipo matriz).fuente
IReadOnlyCollection
no admite acceso indexado, por lo que no se puede usar aquí. Además, likeIReadOnlyList
(que tiene acceso indexado) es susceptible a la manipulación de elementos al volver a enviarlosstring[]
. En otras palabras:ReadOnlyCollection
(a la que no puede convertir una matriz de cadenas) es la solución más sólida. No usar un captador es una opción (y he actualizado la respuesta para tener en cuenta eso), pero con los datos públicos probablemente sea mejor quedarse con una propiedad.Para mis necesidades defino
static
matriz, en lugar de imposibleconst
y funciona:public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
fuente
const
del ejemplo OP también funciona, pero eso (o su respuesta) permite cambiar tanto:Titles
instancia como cualquier valor. Entonces, ¿cuál es el punto en esta respuesta?readonly
const
/readonly
consideración, simplemente haciéndolo funcionar (como siconst
fuera un error de sintaxis). Para algunas personas, parece ser una respuesta valiosa (¿tal vez también intentaron usarlaconst
por error?).Podría adoptar un enfoque diferente: defina una cadena constante para representar su matriz y luego divida la cadena en una matriz cuando la necesite, p. Ej.
Este enfoque le proporciona una constante que puede almacenarse en la configuración y convertirse en una matriz cuando sea necesario.
fuente
En aras de la exhaustividad, ahora también tenemos ImmutableArrays a nuestra disposición. Esto debería ser realmente inmutable:
Requiere System.Collections.Immutable NuGet reference
https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx
fuente
Esta es una manera de hacer lo que quieres:
Es muy similar a hacer una matriz de solo lectura.
fuente
public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
; no es necesario volver a crear la lista en cada recuperación si la convierte en una ReadOnlyCollection de todos modos.Esta es la única respuesta correcta. Actualmente no puedes hacer esto.
Todas las otras respuestas sugieren usar variables estáticas de solo lectura que son similares , pero no iguales a una constante. Una constante está codificada en el ensamblaje. Una variable de solo lectura estática se puede configurar una vez, probablemente a medida que se inicializa un objeto.
Estos a veces son intercambiables, pero no siempre.
fuente
Creo que solo puedes hacer que sea de solo lectura.
fuente
Las matrices son probablemente una de esas cosas que solo se pueden evaluar en tiempo de ejecución. Las constantes deben evaluarse en tiempo de compilación. Intente usar "readonly" en lugar de "const".
fuente
Como alternativa, para solucionar el problema de elementos que se pueden modificar con una matriz de solo lectura, puede usar una propiedad estática en su lugar. (Los elementos individuales aún se pueden cambiar, pero estos cambios solo se realizarán en la copia local de la matriz).
Por supuesto, esto no será particularmente eficiente ya que cada vez se crea una nueva matriz de cadenas.
fuente
Mejor alternativa:
fuente