Qual é a diferença entre const e readonly em C #?

1363

Qual é a diferença entre conste readonlyem c #?

Quando você usaria um sobre o outro?

Somente leitura
fonte
Eu tive que procurar várias respostas para encontrar este link, mas é uma boa. A opinião de Eric Lippert sobre imutabilidade em c # #
Frank Bryce
2
@donstack, na verdade, de acordo com a referência C # , um campo somente leitura pode ser atribuído e reatribuído várias vezes na declaração e no construtor.
Marques

Respostas:

1289

Além da aparente diferença de

  • ter que declarar o valor no momento de uma definição para valores de constVS readonlypode ser calculado dinamicamente, mas precisa ser atribuído antes que o construtor saia .. depois disso, ele é congelado.
  • 'const's são implicitamente static. Você usa uma ClassName.ConstantNamenotação para acessá-los.

Há uma diferença sutil. Considere uma classe definida em AssemblyA.

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly int I_RO_VALUE;
  public Const_V_Readonly()
  {
     I_RO_VALUE = 3;
  }
}

AssemblyBreferencia AssemblyAe usa esses valores no código. Quando isso é compilado,

  • no caso do constvalor, é como uma substituição de localização, o valor 2 é 'incorporado à AssemblyB' IL. Isso significa que, se amanhã eu atualizar I_CONST_VALUEpara 20 no futuro. AssemblyBainda teria 2 até eu recompilar .
  • no caso do readonlyvalor, é como um reflocal de memória. O valor não está inserido AssemblyBna IL. Isso significa que, se o local da memória for atualizado, AssemblyBobtém o novo valor sem recompilação. Portanto, se I_RO_VALUEfor atualizado para 30, você precisará criar apenas AssemblyA. Todos os clientes não precisam ser recompilados.

Portanto, se você estiver confiante de que o valor da constante não mudará, use a const.

public const int CM_IN_A_METER = 100;

Mas se você tem uma constante que pode mudar (por exemplo, precisão de escrita) .. ou em caso de dúvida, use a readonly.

public readonly float PI = 3.14;

Atualização: Aku precisa fazer uma menção porque ele apontou isso primeiro. Também preciso conectar onde aprendi isso. C # eficaz - Bill Wagner

Gishu
fonte
77
O staticponto parece ser o ponto mais importante e útil -consts are implicitly static
LCJ
28
A parte sobre valores de referência é a mais importante. Os valores Const podem ser otimizados.
precisa saber é o seguinte
22
readonlyvariáveis ​​podem ser alteradas fora do construtor (reflexão). É apenas o compilador que tenta impedir você de modificar o var fora do construtor.
Bitterblue
12
As readonlyvariáveis @ mini-me não podem ser alteradas após a conclusão do construtor, mesmo através da reflexão. O tempo de execução não impõe isso. O tempo de execução também acontece para não impor que você não mudar string.Emptypara "Hello, world!", mas eu ainda não diria que isso faz string.Emptymodificáveis, ou que o código não deve assumir que string.Emptyserá sempre uma cadeia de comprimento zero.
7
blogs.msmvps.com/jonskeet/2014/07/16/… é uma interessante leitura apenas do custo de leitura somente
CAD CAD
275

Há uma pegadinha com consts! Se você referenciar uma constante de outra montagem, seu valor será compilado diretamente na montagem de chamada. Dessa forma, quando você atualiza a constante na montagem referenciada, ela não muda na montagem de chamada!

aku
fonte
8
Na descompilação (Reflector, ILSpy, ..), uma constante NUNCA NUNCA é referenciada por ninguém, não importa a mesma montagem ou outra montagem, portanto, você não pode analisar o uso de uma constante no código compilado.
precisa saber é
159

Constantes

  • Constantes são estáticas por padrão
  • Eles devem ter um valor no momento da compilação (você pode ter, por exemplo, 3,14 * 2, mas não pode chamar métodos)
  • Pode ser declarado dentro de funções
  • São copiados para cada montagem que os utiliza (toda montagem obtém uma cópia local dos valores)
  • Pode ser usado em atributos

Campos de instância somente leitura

  • Deve ter um valor definido, no momento em que o construtor sai
  • São avaliados quando a instância é criada

Campos estáticos somente leitura

  • São avaliados quando a execução do código atinge a referência de classe (quando uma nova instância é criada ou um método estático é executado)
  • Deve ter um valor avaliado no momento em que o construtor estático é concluído
  • Não é recomendável colocar ThreadStaticAttribute neles (os construtores estáticos serão executados em apenas um thread e definirão o valor para seu thread; todos os outros threads terão esse valor não inicializado)
splattne
fonte
58

Apenas para adicionar, o ReadOnly somente para tipos de referência torna a referência somente leitura, não os valores. Por exemplo:

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};

  public UpdateReadonly()
  {
     I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
     I_RO_VALUE = new char[]{'V'}; //will cause compiler error
  }
}

fonte
Existe algum outro tipo de referência stringque você possa usar como constante?
precisa saber é
Você pode ter constcom tipos de referência diferentes de sequência, mas a constante pode ter apenas o valor null.
Mike Rosoft
40

Isso explica isso . Resumo: const deve ser inicializado no momento da declaração, somente leitura pode ser inicializado no construtor (e, portanto, ter um valor diferente, dependendo do construtor usado).

EDIT: Veja a pegadinha de Gishu acima para a diferença sutil

Vinko Vrsalovic
fonte
32

const: Não pode ser alterado em lugar nenhum.

readonly: Esse valor pode ser alterado apenas no construtor. Não pode ser alterado em funções normais.

Deepthi
fonte
26

Há uma pequena pegadinha com somente leitura. Um campo somente leitura pode ser definido várias vezes no (s) construtor (es). Mesmo que o valor seja definido em dois construtores encadeados diferentes, ele ainda é permitido.


public class Sample {
    private readonly string ro;

    public Sample() {
        ro = "set";
    }

    public Sample(string value) : this() {
        ro = value; // this works even though it was set in the no-arg ctor
    }
}
Mike Two
fonte
26

Um membro constante é definido no tempo de compilação e não pode ser alterado no tempo de execução. As constantes são declaradas como um campo, usando a constpalavra - chave e devem ser inicializadas conforme são declaradas.

public class MyClass
{
    public const double PI1 = 3.14159;
}

Um readonlymembro é como uma constante, pois representa um valor imutável. A diferença é que um readonlymembro pode ser inicializado em tempo de execução, em um construtor, além de poder ser inicializado conforme declarado.

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

const

  • Eles não podem ser declarados como static (eles são implicitamente estáticos)
  • O valor da constante é avaliado em tempo de compilação
  • constantes são inicializadas apenas na declaração

somente leitura

  • Eles podem ser no nível da instância ou estáticos
  • O valor é avaliado em tempo de execução
  • readonly pode ser inicializado em declaração ou por código no construtor
Sujit
fonte
6
Eles não podem ser estáticos , eles são estáticos. Você deve deixar claro se você quis dizer que não se pode declararstatic const int i = 0;
Nawfal
Você pode explicar por que as constdeclarações não podem ser feitas dentro de métodos?
Minh Tran
21

Uma const é uma constante em tempo de compilação, enquanto que somente leitura permite que um valor seja calculado em tempo de execução e definido no construtor ou inicializador de campo. Portanto, uma 'const' é sempre constante, mas 'readonly' é somente leitura quando é atribuída.

Eric Lippert, da equipe C #, tem mais informações sobre diferentes tipos de imutabilidade

Wheelie
fonte
15

Aqui está outro link demonstra como const não é uma versão segura ou relevante para tipos de referência.

Resumo :

  • O valor da sua propriedade const é definido no tempo de compilação e não pode ser alterado no tempo de execução
  • Const não pode ser marcado como estático - a palavra-chave indica que eles são estáticos, diferentemente dos campos somente leitura que podem.
  • Const não pode ser nada, exceto tipos de valor (primitivo)
  • A palavra-chave readonly marca o campo como imutável. No entanto, a propriedade pode ser alterada dentro do construtor da classe
  • A palavra-chave somente leitura também pode ser combinada com estática para fazê-la agir da mesma maneira que uma const (pelo menos na superfície). Há uma diferença marcante quando você olha para o IL entre os dois
  • os campos const são marcados como "literais" em IL enquanto readonly é "initonly"
Chris S
fonte
11

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

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

Yeasin Abedin Siam
fonte
obrigado por não me fazer ler 4 parágrafos apenas para estes dois take-aways ...
Don Cheadle
6

Eu acredito que um constvalor é o mesmo para todos os objetos (e deve ser inicializado com uma expressão literal), enquanto readonlypode ser diferente para cada instanciação ...

Daren Thomas
fonte
5

Um dos membros da equipe em nosso escritório forneceu as seguintes orientações sobre quando usar const, static e readonly:

  • Use const quando tiver uma variável de um tipo que você possa saber em tempo de execução (string literal, int, double, enums, ...) que deseja que todas as instâncias ou consumidores de uma classe tenham acesso a onde o valor não deve mudar.
  • Use estática quando você tiver dados que deseja que todas as instâncias ou consumidores de uma classe tenham acesso a onde o valor pode mudar.
  • Use estática somente leitura quando você tiver uma variável de um tipo que não possa saber em tempo de execução (objetos) que deseja que todas as instâncias ou consumidores de uma classe tenham acesso a onde o valor não deve ser alterado.
  • Use somente leitura quando tiver uma variável no nível da instância que você saberá no momento da criação do objeto que não deve mudar.

Uma nota final: um campo const é estático, mas o inverso não é verdadeiro.

Scott Lawrence
fonte
1
Eu acho que você quer dizer "conversar". O inverso seria "um campo não-const não é estático". O que pode ou não ser verdade. O contrário, "um campo estático é (sempre) const" não é verdadeiro.
Michael Blackburn
5

Ambos são constantes, mas uma const está disponível também em tempo de compilação. Isso significa que um aspecto da diferença é que você pode usar variáveis ​​const como entrada para atribuir construtores, mas não variáveis ​​somente leitura.

Exemplo:

public static class Text {
  public const string ConstDescription = "This can be used.";
  public readonly static string ReadonlyDescription = "Cannot be used.";
}

public class Foo 
{
  [Description(Text.ConstDescription)]
  public int BarThatBuilds {
    { get; set; }
  }

  [Description(Text.ReadOnlyDescription)]
  public int BarThatDoesNotBuild {
    { get; set; }
  }
}
Hallgrim
fonte
5
  • quando usar constoureadonly

    • const

      • constante em tempo de compilação : constante absoluta , o valor é definido durante a declaração, está no próprio código IL
    • readonly

      • constante de tempo de execução : pode ser definida no construtor / init via arquivo de configuração App.config, mas, uma vez inicializada, não pode ser alterada
Ryan Efendy
fonte
4

As variáveis ​​marcadas como const são pouco mais do que macros #define fortemente tipadas; no tempo de compilação, as referências às variáveis ​​const são substituídas por valores literais embutidos. Como conseqüência, apenas certos tipos de valores primitivos internos podem ser usados ​​dessa maneira. As variáveis ​​marcadas como somente leitura podem ser definidas, em um construtor, no tempo de execução e sua somente leitura é imposta também durante o tempo de execução. Existe um custo menor de desempenho associado a isso, mas significa que você pode usar somente leitura com qualquer tipo (mesmo tipos de referência).

Além disso, variáveis ​​const são inerentemente estáticas, enquanto variáveis ​​readonly podem ser específicas da instância, se desejado.

Cunha
fonte
Adicionado que consts são macros #define fortemente tipadas . Caso contrário, podemos assustar todas as pessoas C ou C ++. :-)
Jason Baker
4

CONST

  1. A palavra-chave const pode ser aplicada a campos ou variáveis ​​locais
  2. Devemos atribuir um campo const no momento da declaração
  3. Nenhuma memória alocada Porque o valor const é incorporado no próprio código IL após a compilação. É como encontrar todas as ocorrências da variável const e substituir por seu valor. Portanto, o código IL após a compilação terá valores codificados no lugar das variáveis ​​const
  4. Const em C # são, por padrão, estáticos.
  5. O valor é constante para todos os objetos
  6. Há um problema de versão da dll - Isso significa que sempre que alteramos uma variável ou propriedade pública const (na verdade, não é para ser alterada teoricamente), qualquer outra dll ou assembly que use essa variável deve ser reconstruída
  7. Somente tipos internos de C # podem ser declarados como constantes
  8. O campo Const não pode ser passado como parâmetro ref ou out

Somente leitura

  1. a palavra-chave readonly se aplica apenas a campos e não a variáveis ​​locais
  2. Podemos atribuir campo somente leitura no momento da declaração ou no construtor, não em nenhum outro método.
  3. memória dinâmica alocada para campos somente leitura e podemos obter o valor em tempo de execução.
  4. O Readonly pertence ao objeto criado, portanto, acessado através apenas da instância da classe. Para torná-lo membro da classe, precisamos adicionar uma palavra-chave estática antes da leitura.
  5. O valor pode ser diferente dependendo do construtor usado (pois pertence ao objeto da classe)
  6. Se você declarar tipos não primitivos (tipo de referência) como somente leitura, a referência será imutável, e não o objeto que ele contém.
  7. Como o valor é obtido no tempo de execução, não há problema de versão da dll com campos / propriedades somente leitura.
  8. Podemos passar o campo somente leitura como parâmetros ref ou out no contexto do construtor.
Muhammad VP
fonte
3

Outra pegadinha .

Como const realmente funciona apenas com tipos de dados básicos, se você deseja trabalhar com uma classe, pode se sentir "forçado" a usar o ReadOnly. No entanto, cuidado com a armadilha! ReadOnly significa que você não pode substituir o objeto por outro (você não pode fazer com que ele se refira a outro objeto). Mas qualquer processo que tenha uma referência ao objeto é livre para modificar os valores dentro do objeto!

Portanto, não se confunda ao pensar que o ReadOnly implica que um usuário não pode mudar as coisas. Não há sintaxe simples em C # para impedir que uma instanciação de uma classe altere seus valores internos (tanto quanto eu sei).

Mark T
fonte
Sim, isso é mais um tema geral. Se você tiver uma propriedade get only expondo uma lista de matrizes, ainda poderá modificar a lista de matrizes. Você não pode definir uma lista de matrizes diferente para essa propriedade, mas não pode impedir o usuário de alterar a lista de matrizes.
Gishu
3

A constdeve ser codificado , onde readonlypode ser definido no construtor da classe.

Greg
fonte
3

Há uma diferença notável entre os campos const e somente leitura em C # .Net

const é, por padrão, estático e precisa ser inicializado com valor constante, que não pode ser modificado posteriormente. Mudança de valor também não é permitida em construtores. 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 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. Portanto, oferece vantagem quando usado como membro da classe de instância. Duas instâncias diferentes podem ter um valor diferente do campo somente leitura. Por ex -

class A
{
    public readonly int Id;

    public A(int i)
    {
        Id = i;
    }
}

Em seguida, o campo somente leitura pode ser inicializado com valores específicos instantâneos, da seguinte maneira:

A objOne = new A(5);
A objTwo = new A(10);

Aqui, a instância objOne terá o valor do campo somente leitura como 5 e objTwo tem 10. O que não é possível usando const.

Chirag
fonte
2

Uma constante será compilada no consumidor como um valor literal, enquanto a sequência estática servirá como uma referência ao valor definido.

Como exercício, tente criar uma biblioteca externa e consumi-la em um aplicativo de console, altere os valores na biblioteca e recompile-a (sem recompilar o programa do consumidor), solte a DLL no diretório e execute o EXE manualmente, você deve encontrar que a cadeia constante não muda.

Brett Ryan
fonte
Sinceramente, duvido que isso seja verdade ... irei verificar.
ljs 8/09/09
esta é uma das 50 maneiras específicas para melhorar o seu C # - amazon.co.uk/Effective-Specific-Ways-Improve-Your/dp/0321245660/...
Russ Cam
@ Andrew Hare - sim, acabei de verificar. Estou muito surpreso, isso é uma verdadeira pegadinha, estou realmente muito surpreso com isso, espantado que seja o caso ...!
ljs 8/09/09
Objeto, no entanto, o uso da palavra ponteiro aqui. Não é um ponteiro, é uma referência, e não é uma diferença em C #, como você pode manipular ponteiros não gerenciados no modo inseguro por isso é importante fazer a distinção entre os dois.
ljs 8/09/09
2

Constante

Precisamos fornecer o valor para o campo const quando ele é definido. O compilador salva o valor da constante nos metadados do assembly. Isso significa que uma constante pode ser definida apenas para o tipo primitivo, como booleano, char, byte e assim por diante. As constantes são sempre consideradas membros estáticos, não membros da instância.

Somente leitura

Os campos somente leitura podem ser resolvidos em tempo de execução. Isso significa que podemos definir um valor para um valor usando o construtor para o tipo em que o campo é declarado. A verificação é feita pelo compilador de que os campos somente leitura não são gravados por nenhum método que não seja o construtor.

Mais sobre os dois explicados aqui neste artigo

Vikram
fonte
1

Principalmente; você pode atribuir um valor a um campo estático somente leitura a um valor não constante em tempo de execução, enquanto uma const deve ser atribuída a um valor constante.

ljs
fonte
1

Const e somente leitura são semelhantes, mas não são exatamente iguais. Um campo const é uma constante em tempo de compilação, o que significa que esse valor pode ser calculado em tempo de compilação. Um campo somente leitura permite cenários adicionais em que algum código deve ser executado durante a construção do tipo. Após a construção, um campo somente leitura não pode ser alterado.

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

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

já que 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 = r;
        green = g;
        blue = b;
    }
}

mas 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 a palavra-chave readonly 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 = r;
        green = g;
        blue = 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
1

ReadOnly: o valor será inicializado apenas uma vez a partir do construtor da classe.
const: pode ser inicializado em qualquer função, mas apenas uma vez

empilhar
fonte
1

A diferença é que o valor de um campo estático somente leitura é definido em tempo de execução, para que ele possa ter um valor diferente para diferentes execuções do programa. No entanto, o valor de um campo const é definido como uma constante de tempo de compilação.

Lembre-se: Para tipos de referência, nos dois casos (estático e instância), o modificador somente leitura impede que você atribua uma nova referência ao campo. Especificamente, não torna imutável o objeto apontado pela referência.

Para obter detalhes, consulte as Perguntas freqüentes em C # sobre este tópico: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx

Yonatan Nir
fonte
1

Variáveis ​​constantes são declaradas e inicializadas em tempo de compilação. O valor não pode ser alterado após as alas. As variáveis ​​somente leitura serão inicializadas apenas no construtor Static da classe. Somente leitura é usado apenas quando queremos atribuir o valor em tempo de execução.

Omar AMEZOUG
fonte
1

Const : valor constante absoluto durante o tempo de vida da aplicação.

Somente leitura : pode ser alterado em tempo de execução.

Olhos grandes
fonte
1
Sua definição de 'Somente leitura' de que ele pode mudar é falha. Eu acho que por 'mudança' você quis dizer 'definir', como 'pode ser definido em tempo de execução'.
Ahmed
0

Uma coisa a acrescentar ao que as pessoas disseram acima. Se você tiver uma montagem contendo um valor somente leitura (por exemplo, somente MaxFooCount = 4;), poderá alterar o valor que os assemblies chamadores veem enviando uma nova versão dessa montagem com um valor diferente (por exemplo, somente MaxFooCount = 5;)

Mas com uma const, seria dobrada no código do chamador quando o compilador fosse compilado.

Se você atingiu esse nível de proficiência em C #, está pronto para o livro de Bill Wagner, C # efetivo: 50 maneiras específicas de melhorar seu C # O que responde a essa pergunta em detalhes (e 49 outras coisas).

Anthony
fonte