A orientação geral para C # é sempre usar uma propriedade em um campo público. Isso faz sentido - ao expor um campo, você expõe muitos detalhes da implementação. Com uma propriedade, você encapsula esses detalhes para que não ocorram o consumo de código, e as alterações na implementação são dissociadas das alterações na interface.
No entanto, estou me perguntando se às vezes há uma exceção válida a essa regra ao lidar com a readonly
palavra - chave. Ao aplicar essa palavra-chave a um campo público, você oferece uma garantia extra: imutabilidade. Este não é apenas um detalhe de implementação; a imutabilidade é algo em que um consumidor pode se interessar. O uso de um readonly
campo faz parte do contrato público e algo que não pode ser quebrado por alterações ou herança futuras sem a necessidade de modificar a interface pública. Isso é algo que uma propriedade não pode oferecer.
Portanto, garantir a imutabilidade é uma razão legítima para escolher um readonly
campo em vez de uma propriedade em alguns casos?
(Para esclarecimento, certamente não estou dizendo que você deve sempre fazer essa escolha apenas porque o campo é imutável no momento, apenas quando faz sentido como parte do design da classe e se seu uso pretendido incluir imutabilidade em seu contrato. Estou interessado principalmente em respostas focadas em saber se isso pode ser justificado, em vez de casos específicos em que não é, como quando você precisa que o membro esteja em um interface
ou deseja fazer um carregamento lento.)
fonte
Respostas:
Campos públicos estáticos somente leitura certamente estão bem. Eles são recomendados para determinadas situações, como quando você deseja um objeto constante e nomeado, mas não pode usar a
const
palavra - chave.Os campos de membros somente leitura são um pouco mais complicados. Não há muita vantagem sobre uma propriedade sem um setter público e há uma grande desvantagem: os campos não podem ser membros de interfaces. Portanto, se você decidir refatorar seu código para operar contra uma interface em vez de um tipo concreto, precisará alterar seus campos somente leitura para propriedades com getters públicos.
Uma propriedade pública não virtual sem um setter protegido fornece proteção contra herança, a menos que as classes herdadas tenham acesso ao campo de suporte. Você pode impor completamente esse contrato na classe base.
Não poder alterar a "imutabilidade" do membro sem alterar a interface pública da classe não é uma grande barreira nesse caso. Geralmente, se você deseja transformar um campo público em uma propriedade, tudo corre bem, exceto que há dois casos com os quais você precisa lidar:
object.Location.X = 4
só é possível seLocation
for um campo. Isso não é relevante para um campo somente leitura, porque você não pode modificar uma estrutura somente leitura. (Isso pressupõe queLocation
é um tipo de valor - caso contrário, esse problema não se aplicaria de qualquer maneira, porquereadonly
não protege contra esse tipo de coisa.)out
ouref
. Novamente, isso não é realmente relevante para um campo somente leitura, porqueout
e osref
parâmetros tendem a ser modificados, e é um erro do compilador passar uma valor somente leitura como out ou ref.Em outras palavras, embora a conversão de um campo somente leitura em uma propriedade somente leitura quebre a compatibilidade binária, outro código-fonte precisaria ser recompilado apenas sem nenhuma alteração para lidar com essa alteração. Isso torna a garantia realmente fácil de quebrar.
Não vejo nenhuma vantagem no
readonly
campo de membro, e a incapacidade de ter esse tipo de coisa em uma interface é uma desvantagem suficiente para mim que eu não a usaria.fonte
Pela minha experiência, a
readonly
palavra-chave não é a mágica que promete.Por exemplo, você tem uma classe em que o construtor costumava ser simples. Dado o uso (e o fato de que algumas propriedades / campos da classe são imutáveis após a construção), você pode pensar que isso não importa, por isso usou a
readonly
palavra - chave.Mais tarde, a classe se torna mais complexa, assim como seu construtor. (Digamos que isso aconteça em um projeto experimental ou que tenha uma velocidade alta o suficiente fora do escopo / controle, mas você precisa fazê-lo funcionar de alguma forma.) Você descobrirá que os campos que
readonly
podem ser modificados somente dentro do construtor - você não pode modificá-lo nos métodos, mesmo que esse método seja chamado apenas de um construtor.Essa limitação técnica foi reconhecida pelos designers do C # e pode ser corrigida em uma versão futura. Mas até que seja corrigido, o uso de
readonly
é mais restritivo e pode incentivar algum estilo de codificação ruim (colocando tudo no método construtor).Como um lembrete,
readonly
nem a propriedade não configuradora pública fornece qualquer garantia de um "objeto totalmente inicializado". Em outras palavras, é o projetista de uma classe que decide o que significa "totalmente inicializado" e como protegê-lo contra o uso inadvertido, e essa proteção geralmente não é infalível, o que significa que alguém pode encontrar uma maneira de contornar isso.fonte
readonly
campo como parâmetroout
ouref
para outros métodos, que estarão livres para modificá-lo como entenderem.Os campos são SEMPRE detalhes de implementação. Você não deseja expor seus detalhes de implementação.
Um princípio fundamental da engenharia de software é que não sabemos quais serão os requisitos no futuro. Embora seu
readonly
campo possa ser bom hoje, não há nada que sugira que ele fará parte dos requisitos de amanhã. E se amanhã for necessário implementar um contador de visitas para determinar quantas vezes esse campo é acessado? E se você precisar permitir que as subclasses substituam o campo?As propriedades são tão fáceis de usar e são muito mais flexíveis que os campos públicos que não consigo pensar em um único caso de uso em que eu escolheria c # como meu idioma e usaria campos públicos somente de leitura em uma classe. Se o desempenho fosse tão baixo que eu não aguentasse a chamada de método extra, provavelmente usaria um idioma diferente.
Só porque nós pode fazer alguma coisa com a língua não significa que deve fazer algo com o idioma.
Eu realmente me pergunto se os designers de idiomas se arrependem de permitir que os campos sejam divulgados. Não me lembro da última vez que considerei usar campos públicos não const no meu código.
fonte
Rational
com público, imutávelNumerator
eDenominator
membros, posso estar extremamente confiante de que esses membros não exigirão carregamento lento ou um contador de visitas ou semelhante?float
tipos paraNumerator
eDenominator
não precisará ser alteradadoubles
?float
nemdouble
. Eles deveriam serint
,long
ouBigInteger
. Talvez eles precisem mudar ... mas, se assim for, também precisariam mudar na interface pública, então realmente usar propriedades não adiciona encapsulamento em torno desses detalhes.Não. Não é uma justificativa.
Usar o readonly como garantia de imutabilidade em não uma justificativa é mais como um hack.
Somente leitura significa que o valor é atribuído por um construtor o quando a variável é definida.
Eu acho que vai ser uma má prática
Se você realmente deseja garantir a imutabilidade, use uma interface com mais prós do que contras.
Exemplo de interface simples:
fonte