Static readonly vs const

1387

Eu li sobre conste static readonlycampos. Temos algumas classes que contêm apenas valores constantes. Usado para várias coisas em nosso sistema. Então, eu estou querendo saber se minha observação está correta:

static readonlyEsse tipo de valor constante deve sempre ser para tudo o que é público? E usar apenas constpara valores internos / protegidos / privados?

O que você recomenda? Talvez eu não deva usar static readonlycampos, mas talvez use propriedades talvez?

Svish
fonte
5
Aqui está um caso único muito interessante que acabei de encontrar static readonly: tente usar uma const dentro de uma IEnumeratorque desencadeie uma irrecuperável yield e você obterá um temido "erro interno do compilador" . Não testei o código fora do Unity3D, mas confio que seja um bug mono ou .NET . É uma questão de c # , no entanto.
Cregox 04/07/2013
2
duplicata possível de Qual é a diferença entre const e readonly?
Nawfal
8
Outra diferença é que você pode usar uma string const em um switch, mas não uma string estática somente leitura
flagg19
7
static readonlynão pode ser usado na switch-caseinstrução como casevariável, consté necessário para esse fim.
Mostafiz Rahman
3
static readonlynão pode ser usado como parâmetro atributo também
Dread Boy

Respostas:

940

public static readonlycampos são um pouco incomuns; public staticpropriedades (com apenas a get) seriam mais comuns (talvez apoiadas por um private static readonlycampo).

constos valores são gravados diretamente no site da chamada; isto é de dois gumes:

  • é inútil se o valor for buscado em tempo de execução, talvez a partir de config
  • se você alterar o valor de uma const, precisará reconstruir todos os clientes
  • mas pode ser mais rápido, pois evita uma chamada de método ...
  • ... que às vezes pode ter sido descrito pelo JIT de qualquer maneira

Se o valor nunca mudar, const estará Zerocorreto - etc, faça considerações razoáveis; p Fora isso, as staticpropriedades são mais comuns.

Marc Gravell
fonte
13
Por que uma propriedade sobre um campo? Se é uma classe imutável, não vejo diferença.
Michael Hedgpeth
73
@ Michael - mesmos motivos de sempre; oculta a implementação. Você pode descobrir (mais tarde) que precisa estar carregado preguiçosamente, com base na configuração, em uma fachada ou qualquer outra coisa. Na realidade, tanto que muitas vezes ficar bem ...
Marc Gravell
42
@CoffeeAddict por definição, uma constante não está obtendo valores de um arquivo de configuração; é gravado como um literal em tempo de compilação. A única maneira de usar uma constante no tempo de execução é através da reflexão sobre os campos. Sempre que você tentar usá-lo, o compilador substituiu o uso constante pelo uso literal ; ou seja, se um método no seu código usa 6 constantes e você o inspeciona como IL, não haverá menção de pesquisas constantes; os valores literais irá simplesmente ser carregado in situ
Marc Gravell
37
@MarcGravell - CUIDADO: os readonlycampos não podem ser usados ​​nas instruções switch / case, você precisa que sejam const.
Luciano
7
@didibus Alterar um campo para uma propriedade, de fato, quebra a API. Um campo em C # atua efetivamente como uma variável, enquanto uma propriedade em C # é um auxiliar de sintaxe para escrever um método getter e / ou um método setter. Essa diferença é importante quando outras montagens estão envolvidas. Se você alterar um campo para uma propriedade, e outros assemblies dependerem desse campo, esses outros assemblies deverão ser recompilados.
Stephen Booher
237

Eu usaria static readonlyse o consumidor estivesse em uma montagem diferente. Ter o conste o consumidor em duas montagens diferentes é uma boa maneira de dar um tiro no próprio pé .

Michael Stum
fonte
5
Portanto, acho que, como alguns já mencionaram ou fizeram alusão, pode ser prudente usar const apenas para valores que são constantes bem conhecidas se forem tornados públicos, caso contrário, devem ser reservados para o escopo de acesso interno, protegido ou privado.
jpierson
1
@Dio A razão pela qual ainda existe é porque não é um problema em si - é algo para estar ciente, mas a capacidade de alinhar as contagens através dos limites da montagem é uma boa coisa para o desempenho. É realmente apenas uma questão de entender realmente que "constante" significa "nunca mudará".
Michael Stum
1
@MichaelStum Ok, não devo chamá-lo de "um problema". Na minha linha de trabalho, eu tenho const e o compartilho entre assemblies, mas recompilo para cada implantação ou remessa de código. No entanto, esse fato definitivamente vale a pena anotá-lo.
Dio Phung 27/02
1
Então, em geral, internal constou public static readonlydependendo da visibilidade desejada.
Iiridayn
2
@Iiridayn Sim, essa não é uma maneira ruim de encarar. Existem alguns casos extremos a serem considerados (por exemplo, se estiver usando o Reflection ou se for necessário um valor em um atributo), e há usos válidos para public const(por exemplo, qualquer parte de um padrão. Sempre que trabalho com XML, há um namespaces com um monte de public const string.) Mas, em geral, public constsó deve ser usado depois de considerar as implicações corretamente.
Michael Stum
200

Poucas coisas mais relevantes a serem observadas:

const int a

  • deve ser inicializado.
  • a inicialização deve estar em tempo de compilação .

readonly int a

  • pode usar um valor padrão, sem inicializar.
  • a inicialização pode ser feita em tempo de execução (Editar: somente no construtor).
Pedro
fonte
39
dentro do ctorúnico.
Amit Kumar Ghosh
1
Não apenas no construtor, mas também na declaração ( docs.microsoft.com/en-us/dotnet/csharp/language-reference/… ).
deChristo 29/08/19
176

Este é apenas um complemento para as outras respostas. Não os repetirei (agora quatro anos depois).

Existem situações em que a conste um não-const têm semântica diferente. Por exemplo:

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

imprime True, enquanto:

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

escreve False.

O motivo é que o método x.Equalspossui duas sobrecargas, uma que aceita um short( System.Int16) e outra que aceita um object( System.Object). Agora, a questão é se um ou ambos se aplicam ao meu yargumento.

Quando yé uma constante em tempo de compilação (literal), consttorna-se importante que exista uma conversão implícita de int para, short desde que intseja uma constante, e desde que o compilador C # verifique se seu valor está dentro do intervalo de a short( qual 42é). Consulte Conversões implícitas de expressão constante na Especificação de idioma do C #. Portanto, as duas sobrecargas devem ser consideradas. A sobrecarga Equals(short)é preferida (qualquer shortum é object, mas nem todos objectsão short). Então, yé convertido em shorte essa sobrecarga é usada. Então Equalscompara dois shortde valor idêntico, e isso dá true.

Quando ynão é uma constante, não existe conversão implícita de intpara short. Isso ocorre porque, em geral, um intpode ser grande demais para caber em um short. (Existe uma conversão explícita , mas eu não disse Equals((short)y), portanto isso não é relevante.) Vemos que apenas uma sobrecarga se aplica, a Equals(object)única. Então yestá na caixa para object. Então, Equalsvocê comparará a System.Int16a System.Int32e, como os tipos de tempo de execução nem sequer concordam, isso renderá false.

Concluímos que, em alguns casos (raros), alterar um constmembro do tipo para um static readonlycampo (ou de outra forma, quando possível) pode alterar o comportamento do programa.

Jeppe Stig Nielsen
fonte
17
Um bom complemento para a resposta aceita. Gostaria de acrescentar que a conversão adequada de tipos de dados e outras diretrizes semelhantes (como try catchs etc.) devem ser um grampo de programadores experientes e não deixadas para o compilador. No entanto, aprendi algo novo a partir daqui. Obrigado.
Uknight
Uau, estou programando em C # há muito tempo e nunca imaginaria que uma const int dentro do intervalo de um curto pudesse ser implicitamente convertida em um curto. Devo dizer que é bastante estranho. Eu amo C #, mas essas inconsistências estranhas que parecem não agregar muito valor, mas acrescentam muita capacidade cerebral necessária para serem constantemente consideradas, podem ser irritantes, especialmente para iniciantes.
Mike Marynowski
@MikeMarynowski É verdade. Mas acho que eles fizeram essa regra (entre outros motivos) para tornar a declaração short x = 42;legal. Porque aí você tem um int, ou seja, o literal 42, que é implicitamente transformado em short x. Mas então, eles podem ter restringido isso a apenas literais numéricos; no entanto, eles escolheram permitir também coisas como short x = y;onde yé definido como const int y = 42;e depois acabaram com isso.
Jeppe Stig Nielsen
88

Uma coisa a notar é que const é restrito a tipos primitivos / de valor (a exceção são as strings)

Chris S
fonte
30
Na verdade, constpoderia ser utilizado para outros tipos também, exceto que ele tem de ser inicializado como nulo, o que torna inútil :)
Nawfal
6
exceção como em System.Exception? :)
Memet Olsen
4
@nawfal Mais precisamente, os únicos tipos de valor para as quais constpodem ser utilizadas, são sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, acrescido de quaisquer enumtipos. constnão pode ser usado para outros tipos de valor, como DateTimeou TimeSpanou BigInteger. Também não pode ser usado para a IntPtrstruct (considerado um tipo "primitivo" por alguns; o termo tipo primitivo é confuso em C #). ↵↵ constPode ser usado para todos os tipos de referência . Se o tipo for string, qualquer valor de sequência poderá ser especificado. Caso contrário, o valor deve ser null.
Jeppe Stig Nielsen
@JeppeStigNielsen - recentemente tive uma discussão com servy sobre isso - ele apontou que você pode fazer qualquer coisa (tipos de valor e referência) constusando default. Para structtipos, é uma instância com todos os seus membros configurados para os valores padrão.
Wai Ha Lee
28

Somente leitura estática : o valor pode ser alterado por meio destatic construtor em tempo de execução. Mas não através da função membro.

Constante : Por padrãostatic . O valor não pode ser alterado de qualquer lugar (Ctor, Função, tempo de execução etc, não-onde).

Somente leitura : o valor pode ser alterado através do construtor em tempo de execução. Mas não através da função membro.

Você pode dar uma olhada no meu repositório: tipos de propriedade C # .

Yeasin Abedin Siam
fonte
1
Más notícias ... link quebrado!
Fer R
Bons trechos Siam :)
Muhammad Ashikuzzaman
25

A readonlypalavra-chave é diferente da constpalavra - chave. Um constcampo só pode ser inicializado na declaração do campo. Um readonlycampo pode ser inicializado na declaração ou em um construtor. Portanto, os readonlycampos podem ter valores diferentes, dependendo do construtor usado. Além disso, enquanto um constcampo é uma constante em tempo de compilação, o readonlycampo pode ser usado para constantes de tempo de execução

Referência curta e clara do MSDN aqui

yazanpro
fonte
16

const e readonly são semelhantes, mas não são exatamente iguais.

Um constcampo é uma constante em tempo de compilação, o que significa que esse valor pode ser calculado em tempo de compilação. Um readonlycampo permite cenários adicionais em que algum código deve ser executado durante a construção do tipo. Após a construção, umreadonly campo não pode ser alterado.

Por exemplo, os constmembros podem ser usados ​​para definir membros como:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

Como valores como 3,14 e 0 são constantes em tempo de compilação. No entanto, considere o caso em que você define um tipo e deseja fornecer algumas instâncias pré-fabricadas. Por exemplo, você pode definir uma classe Color e fornecer "constantes" para cores comuns, como preto, branco etc. Não é possível fazer isso com membros const, pois o lado direito não é uma constante em tempo de compilação. Pode-se fazer isso com membros estáticos regulares:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red   = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

Porém, não há nada que impeça um cliente da Color de trocá-lo, talvez trocando os valores de preto e branco. Escusado será dizer que isso causaria consternação para outros clientes da classe Color. O recurso "somente leitura" aborda esse cenário.

Simplesmente introduzindo o readonly palavra chave nas declarações, preservamos a inicialização flexível e impedimos que o código do cliente mexa.

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red   = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

É interessante notar que os membros const são sempre estáticos, enquanto um membro somente leitura pode ser estático ou não, assim como um campo regular.

É possível usar uma única palavra-chave para esses dois propósitos, mas isso leva a problemas de versão ou de desempenho. Suponhamos por um momento que usamos uma única palavra-chave para isso (const) e um desenvolvedor escreveu:

public class A
{
    public static const C = 0;
}

e um desenvolvedor diferente escreveu um código que contava com A:

public class B
{
    static void Main() => Console.WriteLine(A.C);
}

Agora, o código gerado pode confiar no fato de que o AC é uma constante em tempo de compilação? Ou seja, o uso de AC pode simplesmente ser substituído pelo valor 0? Se você disser "sim" a isso, isso significa que o desenvolvedor de A não pode mudar a maneira como o CA é inicializado - isso amarra as mãos do desenvolvedor de A sem permissão.

Se você disser "não" a esta pergunta, uma otimização importante será perdida. Talvez o autor de A tenha certeza de que AC sempre será zero. O uso de const e readonly permite que o desenvolvedor de A especifique a intenção. Isso contribui para um melhor comportamento de versão e também um melhor desempenho.

Ramesh Rajendran
fonte
12

Minha preferência é usar const sempre que possível, o que, como mencionado acima, se limita a expressões literais ou a algo que não requer avaliação.

Se eu me deparar com essa limitação, recorro à estática somente leitura , com uma ressalva. Geralmente, eu usaria uma propriedade estática pública com um getter e um campo estático privado de backup, conforme Marc menciona aqui .

Peter Meyer
fonte
7

Const: Const nada mais é do que "constante", uma variável cujo valor é constante, mas em tempo de compilação. E é obrigatório atribuir um valor a ele. Por padrão, uma const é estática e não podemos alterar o valor de uma variável const em todo o programa.

ReadOnly estático: o valor de uma variável do tipo Static Readonly pode ser atribuído no tempo de execução ou atribuído no tempo de compilação e alterado no tempo de execução. Mas o valor dessa variável só pode ser alterado no construtor estático. E não pode ser alterado mais. Pode mudar apenas uma vez em tempo de execução

Referencia: c-sharpcorner

mayank
fonte
6

Um campo estático somente leitura é vantajoso ao expor a outros assemblies um valor que pode ser alterado em uma versão posterior.

Por exemplo, suponha que a montagem Xexponha uma constante da seguinte maneira:

public const decimal ProgramVersion = 2.3;

Se a montagem Yreferenciar Xe usar essa constante, o valor 2.3 será inserido na montagem Yquando compilado. Isso significa que, se Xmais tarde for recompilado com a constante definida como 2.4, Yainda usará o valor antigo de 2.3 até que Yseja recompilado. Um campo estático somente leitura evita esse problema.

Outra maneira de analisar isso é que qualquer valor que possa mudar no futuro não é constante por definição e, portanto, não deve ser representado como um.

Yagnesh Cangi
fonte
3

const:

  1. valor deve ser dado mediante declaração
  2. compilar constante de tempo

somente leitura:

  1. pode ser fornecido na declaração ou durante o tempo de execução usando construtores. O valor pode variar dependendo do construtor usado.
  2. tempo de execução constante
dasumohan89
fonte
3

Const : os valores das variáveis ​​const precisam definir junto com a declaração e depois disso não será alterado. const são implicitamente estáticos, portanto, sem criar instância de classe, podemos acessá-los. isso tem um valor em tempo de compilação

ReadOnly : valores de variável readonly que podemos definir ao declarar e também ao usar o construtor em tempo de execução. variáveis ​​readonly não podem acessar sem instância de classe.

Static readonly : valores de variável estática readonly que podemos definir ao declarar, bem como apenas através do construtor estático, mas não com qualquer outro construtor. Essas variáveis ​​também podemos acessar sem criar instância de classe (como variáveis ​​estáticas).

readonly estático será a melhor escolha se tivermos que consumir as variáveis ​​em diferentes montagens. Verifique os detalhes completos no link abaixo

https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yourself-in-the-foot/

user1756922
fonte
Você poderia me dizer por que recusou a resposta, para que eu possa me atualizar também aqui.
user1756922
Não é o DV, mas pode ser que essa resposta realmente não adicione nada às respostas já abrangentes aqui.
Marc L.
de fato, lembre-se de que em Java, no final dos anos 90, tínhamos em um projeto várias pessoas produzindo jarros diferentes com arquivos de classe que interoperavam (referenciados uns aos outros) e a cadeia const pública apresentava problemas de versão, uma vez que estavam sendo copiados
George Birbilis
2

Há uma pequena diferença entre os campos const e estático somente leitura em C # .Net

const deve ser inicializado com valor em tempo de compilação.

const é, por padrão, estático e precisa ser inicializado com valor constante, que não pode ser modificado posteriormente. Não pode ser usado com todos os tipos de dados. Por ex DateTime. Não pode ser usado com o tipo de dados DateTime.

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public static readonly string Name = string.Empty; //No error, legal

readonly pode ser declarado como estático, mas não necessário. Não há necessidade de inicializar no momento da declaração. Seu valor pode ser atribuído ou alterado usando o construtor uma vez. Portanto, existe a possibilidade de alterar o valor do campo somente leitura uma vez (não importa, se é estático ou não), o que não é possível com const.

Chirag
fonte
0

Constantes são como o nome indica, campos que não mudam e geralmente são definidos estaticamente em tempo de compilação no código.

Variáveis ​​somente leitura são campos que podem ser alterados sob condições específicas.

Eles podem ser inicializados quando você os declara como uma constante, mas geralmente são inicializados durante a construção do objeto dentro do construtor.

Eles não podem ser alterados após a inicialização, nas condições mencionadas acima.

Somente leitura estática soa como uma má escolha para mim, pois, se é estático e nunca muda, use-o public const; se puder mudar, não será uma constante e, dependendo de suas necessidades, você poderá usar a leitura -só ou apenas uma variável regular.

Além disso, outra distinção importante é que uma constante pertence à classe, enquanto a variável somente leitura pertence à instância!

Claudiu Cojocaru
fonte
0

Uma const (sendo determinada em tempo de compilação) pode ser usada nos casos em que uma estática somente leitura não pode, como em instruções switch, ou construtores de atributos. Isso ocorre porque os campos somente leitura são resolvidos apenas em tempo de execução e algumas construções de código exigem garantia de tempo de compilação. Uma estática somente leitura pode ser calculada em um construtor, o que geralmente é uma coisa essencial e útil. A diferença é funcional, como deve ser o uso deles na minha opinião.

Em termos de alocação de memória, pelo menos com seqüências de caracteres (sendo um tipo de referência), parece não haver diferença, pois ambas são internadas e farão referência à instância internada.

Pessoalmente, meu padrão é apenas estático, pois faz mais sentido semântico e lógico para mim, principalmente porque a maioria dos valores não é necessária no momento da compilação. E, a propósito, as estáticas públicas somente para leitura não são incomuns ou incomuns, como afirma a resposta marcada: por exemplo, System.String.Emptyé uma.

DvS
fonte
0

Outra diferença entre declarar const e static readonly está na alocação de memória.

Um campo estático pertence ao tipo de um objeto e não a uma instância desse tipo. Como resultado, uma vez que a classe é referenciada pela primeira vez, o campo estático "permanece" na memória pelo resto do tempo, e a mesma instância do campo estático é referenciada por todas as instâncias do tipo.

Por outro lado, um campo const "pertence a uma instância do tipo.

Se a memória da desalocação for mais importante para você, prefira usar const . Se velocidade, use estática somente leitura .

Boris Lipschitz
fonte