Quais são os benefícios de ter uma variável de membro declarada como somente leitura? É apenas uma proteção contra alguém que altera seu valor durante o ciclo de vida da classe ou o uso dessa palavra-chave resulta em melhorias de velocidade ou eficiência?
295
readonly
campos dos tipos de estrutura impõem uma penalidade de desempenho em comparação com os campos mutáveis que simplesmente não são mutados, pois a chamada de qualquer membro de umreadonly
campo de tipo de valor fará com que o compilador faça uma cópia do campo e invoque o membro nisso.Respostas:
A
readonly
palavra-chave é usada para declarar uma variável de membro uma constante, mas permite que o valor seja calculado em tempo de execução. Isso difere de uma constante declarada com oconst
modificador, que deve ter seu valor definido no tempo de compilação. Usandoreadonly
você pode definir o valor do campo na declaração ou no construtor do objeto do qual o campo é membro.Use-o também se não desejar recompilar DLLs externas que fazem referência à constante (pois ela é substituída no momento da compilação).
fonte
Não acredito que haja ganhos de desempenho ao usar um campo somente leitura. É simplesmente uma verificação para garantir que, uma vez que o objeto esteja totalmente construído, esse campo não possa ser apontado para um novo valor.
No entanto, "somente leitura" é muito diferente de outros tipos de semântica somente leitura porque é imposta em tempo de execução pelo CLR. A palavra-chave readonly é compilada em .initonly, que é verificável pelo CLR.
A vantagem real dessa palavra-chave é gerar estruturas de dados imutáveis. Estruturas de dados imutáveis por definição não podem ser alteradas depois de construídas. Isso facilita muito o raciocínio sobre o comportamento de uma estrutura em tempo de execução. Por exemplo, não há perigo de passar uma estrutura imutável para outra parte aleatória do código. Eles nunca podem mudar isso para que você possa programar de forma confiável com base nessa estrutura.
Aqui está uma boa entrada sobre um dos benefícios da imutabilidade: rosqueamento
fonte
Não há benefícios aparentes no desempenho do uso
readonly
, pelo menos nenhum que eu já tenha mencionado em qualquer lugar. É apenas para fazer exatamente o que você sugere, para impedir a modificação depois que ela for inicializada.Portanto, é benéfico, pois ajuda a escrever um código mais robusto e legível. O benefício real de coisas como essa ocorre quando você está trabalhando em equipe ou em manutenção. Declarar algo
readonly
semelhante a colocar um contrato para o uso dessa variável no código. Pense nisso como adicionar documentação da mesma maneira que outras palavras-chave comointernal
ouprivate
, você está dizendo "essa variável não deve ser modificada após a inicialização" e, além disso, você a está aplicando .Portanto, se você criar uma classe e marcar algumas variáveis de membro
readonly
por design, evite que você ou outro membro da equipe cometa um erro mais tarde ao expandir ou modificar sua classe. Na minha opinião, esse é um benefício que vale a pena ter (às custas da complexidade extra do idioma, como a doofledorfer menciona nos comentários).fonte
Para colocar em termos muito práticos:
Se você usar uma const na DLL A e na DLL B fizer referência a essa const, o valor dessa const será compilado na DLL B. Se você reimplementar a DLL A com um novo valor para essa const, a DLL B continuará usando o valor original.
Se você usar um readonly nas referências da DLL A e da DLL B que somente leitura, essa leitura sempre será pesquisada em tempo de execução. Isso significa que, se você reimplementar a DLL A com um novo valor somente para isso, a DLL B usará esse novo valor.
fonte
const
pode ter ganho de desempenho acimareadonly
. Aqui está uma explicação um pouco mais profunda com o código: dotnetperls.com/readonlyreadonly
campos. Você não pode armazenar umnew object();
em umconst
e isso faz sentido porque você não pode criar coisas sem valor, como referências em outros assemblies durante o tempo de compilação sem alterar a identidade.Há um caso potencial em que o compilador pode fazer uma otimização de desempenho com base na presença da palavra-chave somente leitura.
Isso se aplica apenas se o campo somente leitura também estiver marcado como estático . Nesse caso, o compilador JIT pode assumir que esse campo estático nunca será alterado. O compilador JIT pode levar isso em consideração ao compilar os métodos da classe.
Exemplo típico: sua classe pode ter um campo IsDebugLoggingEnabled estático, somente leitura , que é inicializado no construtor (por exemplo, com base em um arquivo de configuração). Depois que os métodos reais são compilados JIT, o compilador pode omitir partes inteiras do código quando o log de depuração não está ativado.
Eu não verifiquei se essa otimização está realmente implementada na versão atual do compilador JIT, então isso é apenas especulação.
fonte
Lembre-se de que o readonly se aplica apenas ao valor em si; portanto, se você estiver usando um tipo de referência, o readonly apenas protegerá a referência de alterações. O estado da instância não é protegido por somente leitura.
fonte
Não esqueça que existe uma solução alternativa para obter os
readonly
campos definidos fora de qualquer construtor usandoout
parâmetros.Um pouco confuso, mas:
Discussões adicionais aqui: http://www.adamjamesnaylor.com/2013/01/23/Setting-Readonly-Fields-From-Chained-Constructors.aspx
fonte
out
..Surpreendentemente, somente leitura pode resultar em código mais lento, como Jon Skeet descobriu ao testar sua biblioteca Noda Time. Nesse caso, um teste executado em 20 segundos levou apenas 4 segundos após a remoção somente leitura.
https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/
fonte
readonly struct
C # 7.2, o benefício de tornar o campo não-somente leitura desaparece.Se você possui um valor pré-definido ou pré-calculado que precisa permanecer o mesmo durante todo o programa, deve-se usar constante, mas se tiver um valor que precise ser fornecido no tempo de execução, mas, uma vez atribuído, deverá permanecer o mesmo durante todo o programa. somente leitura. por exemplo, se você precisar atribuir a hora de início do programa ou armazenar um valor fornecido pelo usuário na inicialização do objeto e precisar restringi-lo de outras alterações, use somente leitura.
fonte
Adicionando um aspecto básico para responder a esta pergunta:
As propriedades podem ser expressas como somente leitura, deixando de fora o
set
operador. Portanto, na maioria dos casos, você não precisará adicionar areadonly
palavra-chave às propriedades:Em contraste com isso: os campos precisam da
readonly
palavra-chave para obter um efeito semelhante:Portanto, um benefício de marcar um campo como
readonly
pode ser obter um nível de proteção contra gravação semelhante a uma propriedade semset
operador - sem ter que alterar o campo para uma propriedade, se por qualquer motivo, isso for desejado.fonte
Cuidado com matrizes particulares somente de leitura. Se eles forem expostos a um cliente como um objeto (você pode fazer isso para interoperabilidade COM como eu fiz), o cliente poderá manipular os valores da matriz. Use o método Clone () ao retornar uma matriz como um objeto.
fonte
ReadOnlyCollection<T>
vez de uma matriz.ImmutableArray<T>
, o que evita o boxe para uma interface (IReadOnlyList<T>
) ou quebra de classe (ReadOnlyCollection
). Ele tem desempenho comparável ao matrizes nativas: blogs.msdn.microsoft.com/dotnet/2013/06/24/...Pode haver um benefício de desempenho no WPF, pois elimina a necessidade de DependencyProperties caras. Isso pode ser especialmente útil com coleções
fonte
Outra parte interessante do uso da marcação somente leitura pode proteger o campo da inicialização no singleton.
por exemplo, no código de csharpindepth :
O readonly desempenha um pequeno papel de proteger o campo Singleton de ser inicializado duas vezes. Outro detalhe é que, para o cenário mencionado, você não pode usar const, porque const força a criação durante o tempo de compilação, mas o singleton faz a criação em tempo de execução.
fonte
readonly
pode ser inicializado na declaração ou obter seu valor apenas do construtor. Ao contrárioconst
, deve ser inicializado e declarado ao mesmo tempo.readonly
tem tudoconst
, além da inicialização do construtorcódigo https://repl.it/HvRU/1
fonte