Declarar uma matriz const

458

É possível escrever algo semelhante ao seguinte?

public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
Jaime Oro
fonte
static pode ser usado, string estática pública [] Titles = new string [] {"German", "Spanish"};
Ray

Respostas:

691

Sim, mas você precisa declá-lo em readonlyvez de const:

public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

O motivo é que constsó pode ser aplicado a um campo cujo valor é conhecido em tempo de compilação. O inicializador de matriz que você mostrou não é uma expressão constante em C #, portanto, produz um erro no compilador.

Declarar que readonlyresolve esse problema porque o valor não é inicializado até o tempo de execução (embora seja garantido que ele tenha sido inicializado antes da primeira vez que a matriz é usada).

Dependendo do que você deseja alcançar, considere também declarar uma enumeração:

public enum Titles { German, Spanish, Corrects, Wrongs };
Cody Gray
fonte
115
Observe que a matriz aqui não é somente leitura, é claro; Títulos [2] = "galês"; funcionaria bem em tempo de execução
Marc Gravell
46
Você provavelmente quer estática demais
tymtam
4
que tal declarar uma matriz "const" em um corpo de método, não na classe um?
Serhio
19
Desculpe pelo voto negativo, mas const também implica estática. Declarar a matriz como somente leitura não está perto de uma solução alternativa. ele precisa readonly staticter alguma semelhança com a semântica solicitada.
Anton
3
@Anton, você e seus "seguidores" removeram votos negativos? Para mim, staticnão é necessário fazê-lo funcionar, basta adicionar a possibilidade de fazer referência Titlessem ter instância, mas remover a possibilidade de alterar o valor para diferentes instâncias (por exemplo, você pode ter um construtor com parâmetro, dependendo do valor desse readonlycampo).
Sinatr 24/03/16
57

Você pode declarar a matriz como readonly, mas lembre-se de que pode alterar o elemento da readonlymatriz.

public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";

Considere usar enum, como sugerido por Cody, ou IList.

public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
Branimir
fonte
31
No .NET 4.5 e superior, você pode declarar uma lista como IReadOnlyList <string> em vez de IList <string>.
Grzegorz Smulko
Só para esclarecer, você ainda pode alterar os valores em um IReadOnlyList (apenas não adicionar ou remover elementos). Mas sim, declarar como um IReadOnlyList seria melhor que um IList.
KevinVictor 13/04
A pergunta é sobre constNÃO readonly...
Yousha Aleayoub
51

Você não pode criar uma matriz 'const' porque matrizes são objetos e só podem ser criadas em tempo de execução e entidades const são resolvidas em tempo de compilação.

O que você pode fazer é declarar sua matriz como "somente leitura". Isso tem o mesmo efeito que const, exceto que o valor pode ser definido em tempo de execução. Só pode ser definido uma vez e, posteriormente, é um valor somente leitura (ou seja, const).

JAiro
fonte
2
Este post destaques por matrizes não podem ser declarados como constantes
Radderz
1
É possível declarar uma matriz constante; o problema é inicializá-lo com um valor constante. O único exemplo de trabalho que vem à mente é o const int[] a = null;que não é muito útil, mas, na verdade, uma instância de uma constante de matriz.
waldrumpus
Esta é a única resposta correta.
Yousha Aleayoub
17

Desde o C # 6, você pode escrever como:

public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };

Veja também: C #: o C # 6.0 novo e aprimorado (especificamente o capítulo "Funções e propriedades corporativas da expressão")

Isso criará uma propriedade estática somente leitura, mas ainda permitirá que você altere o conteúdo da matriz retornada, mas quando você chamar a propriedade novamente, obterá a matriz original inalterada novamente.

Para esclarecimento, esse código é o mesmo que (ou na verdade é uma abreviação de):

public static string[] Titles
{
    get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}

Observe que há uma desvantagem nessa abordagem: Na verdade, uma nova matriz é instanciada em todas as referências; portanto, se você estiver usando uma matriz muito grande, essa pode não ser a solução mais eficiente. Mas se você reutilizar a mesma matriz (colocando-a em um atributo privado, por exemplo), ela abrirá novamente a possibilidade de alterar o conteúdo da matriz.

Se você deseja ter uma matriz imutável (ou lista), também pode usar:

public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };

Mas isso ainda corre o risco de alterações, pois você ainda pode convertê-lo em uma string [] e alterar o conteúdo, como tal:

((string[]) Titles)[1] = "French";
mjepson
fonte
1
Qual é o lucro de usar propriedade em vez de campo neste caso?
Nicolay.anykienko 12/12/16
2
Um campo não pode retornar um novo objeto em cada chamada. Uma propriedade é basicamente uma espécie de "função disfarçada".
mjepson
1
Se você estava se referindo à última opção, isso pode ser feito usando um campo ou uma propriedade, mas, como é pública, prefiro uma Propriedade. Eu nunca uso um campo público desde a introdução das Propriedades.
mjepson
1
Há outra desvantagem na primeira abordagem: você não receberá um erro de compilação se atribuir a Titles[0], por exemplo - na verdade, a tentativa de atribuição é silenciosamente ignorada. Combinado com a ineficiência de recriar a matriz sempre, pergunto-me se vale a pena mostrar essa abordagem. Por outro lado, a segunda abordagem é eficiente e você precisa se esforçar para derrotar a imutabilidade.
usar o seguinte comando
6

Se você declarar uma matriz atrás de uma interface IReadOnlyList, obterá uma matriz constante com valores constantes declarados em tempo de execução:

public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };

Disponível no .NET 4.5 e superior.

Richard Garside
fonte
6

Uma solução do .NET Framework v4.5 + que aprimora a resposta do tdbeckett :

using System.Collections.ObjectModel;

// ...

public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
  new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);

Nota: Como a coleção é conceitualmente constante, pode fazer sentido staticdeclará-la no nível da classe .

O de cima:

  • Inicializa o campo implícito de apoio da propriedade uma vez com a matriz.

    • Observe que { get; }- ou seja, declarar apenas um getter de propriedade - é o que torna a propriedade implicitamente somente leitura (tentar combinar readonlycom isso { get; }é na verdade um erro de sintaxe).

    • Como alternativa, você pode simplesmente omitir { get; }e adicionar readonlypara criar um campo em vez de uma propriedade, como na pergunta, mas expor membros de dados públicos como propriedades em vez de campos é um bom hábito.

  • Cria uma estrutura semelhante a uma matriz (permitindo acesso indexado ) que é verdadeira e robusta somente leitura (conceitualmente constante, uma vez criada), ambas com relação a:

    • impedindo a modificação da coleção como um todo (como remover ou adicionar elementos ou atribuir uma nova coleção à variável).
    • impedindo a modificação de elementos individuais .
      (Mesmo indireta modificação não é possível - ao contrário de uma IReadOnlyList<T>solução, onde um (string[])elenco pode ser usado para ganhar acesso de gravação para os elementos , como mostrado na resposta útil das mjepsen .
      A mesma vulnerabilidade se aplica à IReadOnlyCollection<T> interface de que, apesar da semelhança no nome para a classe ReadOnlyCollection , nem mesmo suporta acesso indexado , tornando-o fundamentalmente inadequado para fornecer acesso semelhante a um array.)
mklement0
fonte
1
@ortb: Infelizmente, IReadOnlyCollectionnão suporta acesso indexado, por isso não pode ser usado aqui. Além disso, like IReadOnlyList(que tem acesso indexado) é suscetível à manipulação de elementos ao converter de volta para string[]. Em outras palavras: ReadOnlyCollection(para a qual você não pode converter uma matriz de cadeias) é a solução mais robusta. Não usar um getter é uma opção (e atualizei a resposta para observar isso), mas com dados públicos é provavelmente melhor ficar com uma propriedade.
precisa saber é o seguinte
5

Para minhas necessidades, defino staticarray, em vez de impossível conste funciona: public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

ALZ
fonte
1
Simplesmente remover constdo exemplo OP também funciona, mas isso (ou sua resposta) permite alterar: Titlesinstância e qualquer valor. Então, qual é o ponto nesta resposta?
Sinatr 24/03/16
@ Sinin, eu respondi isso há 3 anos, quando comecei a trabalhar em C #. Deixei, agora estou no mundo Java. Talvez eu esqueci de acrescentarreadonly
ALZ
Pensando bem, sua resposta é direta sobre como fazer o código OP funcionar , sem nenhuma const/ readonlyconsideração, simplesmente fazê-lo funcionar (como se constfosse um erro de sintaxe). Para algumas pessoas, parece ser uma resposta valiosa (talvez elas também tenham tentado usar constpor engano?).
Sinatr 29/03/16
5

Você pode adotar uma abordagem diferente: defina uma string constante para representar sua matriz e depois divida a string em uma matriz quando precisar, por exemplo

const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');

Essa abordagem fornece uma constante que pode ser armazenada na configuração e convertida em uma matriz quando necessário.

Alastair
fonte
8
Penso que o custo de realizar a divisão ultrapassa em muito os benefícios obtidos com a definição de const. Mas +1 para uma abordagem única e para pensar fora da caixa! ;)
Radderz 15/10
Eu estava prestes a postar a mesma solução e vi isso, ao contrário das observações duras e negativas, isso foi realmente perfeito para o meu cenário, onde eu precisava passar uma const para um Atributo e, em seguida, dividi o valor no construtor de atributo para conseguir o que eu precisava. e não vejo nenhuma razão pela qual ele terá custo de desempenho, pois os atributos não são criados para cada instância.
Kalpesh Popat 03/10/19
4

Por uma questão de completude, agora também temos o ImmutableArrays à nossa disposição. Isso deve ser verdadeiramente imutável:

public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });

Requer referência System.Collections.Immutable NuGet

https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx

shurik
fonte
3

Esta é uma maneira de fazer o que você deseja:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}

É muito semelhante a fazer uma matriz somente leitura.

tdbeckett
fonte
8
Você pode fazer isso como public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();; não é necessário recriar a lista em todas as recuperações, se você a tornar uma ReadOnlyCollection de qualquer maneira.
Nyerguds
3

Esta é a única resposta correta. Você não pode fazer isso no momento.

Todas as outras respostas sugerem o uso de variáveis ​​estáticas somente leitura, que são semelhantes a , mas não iguais a uma constante. Uma constante é codificada no conjunto. Uma variável estática de somente leitura é configurável uma vez, provavelmente quando um objeto é inicializado.

Às vezes são intercambiáveis, mas nem sempre.

Roger Hill
fonte
2

Eu acredito que você só pode fazê-lo somente para leitura.

skaz
fonte
2

Matrizes são provavelmente uma daquelas coisas que só podem ser avaliadas em tempo de execução. As constantes devem ser avaliadas em tempo de compilação. Tente usar "somente leitura" em vez de "const".

nemke
fonte
0

Como alternativa, para contornar o problema de elementos que podem ser modificados com uma matriz somente leitura, você pode usar uma propriedade estática. (Os elementos individuais ainda podem ser alterados, mas essas alterações serão feitas apenas na cópia local da matriz.)

public static string[] Titles 
{
    get
    {
        return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
    }
}

Obviamente, isso não será particularmente eficiente, pois uma nova matriz de strings será criada a cada vez.

Hutch
fonte
0

Melhor alternativa:

public static readonly byte[] ZeroHash = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Herman Schoenfeld
fonte