Eu tenho uma classe com dois readonly int
campos. Eles são expostos como propriedades:
public class Thing
{
private readonly int _foo, _bar;
/// <summary> I AM IMMUTABLE. </summary>
public Thing(int foo, int bar)
{
_foo = foo;
_bar = bar;
}
public int Foo { get { return _foo; } set { } }
public int Bar { get { return _bar; } set { } }
}
No entanto, isso significa que o seguinte é um código perfeitamente legal:
Thing iThoughtThisWasMutable = new Thing(1, 42);
iThoughtThisWasMutable.Foo = 99; // <-- Poor, mistaken developer.
// He surely has bugs now. :-(
Os erros que advêm da suposição de que funcionariam certamente serão insidiosos. Claro, o desenvolvedor errado deve ter lido os documentos. Mas isso não muda o fato de que nenhum erro de compilação ou tempo de execução o alertou sobre o problema.
Como a Thing
classe deve ser alterada para que os desenvolvedores tenham menos probabilidade de cometer o erro acima?
Lançar uma exceção? Use um método getter em vez de uma propriedade?
c#
object-oriented
immutability
properties
kdbanman
fonte
fonte
Interfaces
. Não tenho certeza se é isso que estou fazendo.Respostas:
Por que tornar esse código legal?
Retire o
set { }
que não faz nada.É assim que você define uma propriedade pública somente leitura:
fonte
public int Foo { get; }
(propriedade automática com apenas um getter) Maspublic int Foo { get; private set; }
é.Com o C # 5 e antes, nos deparamos com duas opções para campos imutáveis expostos por meio de um getter:
readonly
o arquivo para destruir a imutabilidade. No entanto, ele criou muitos códigos de placas de caldeira.No entanto, com o C # 6 (disponível no VS2015, lançado ontem), agora obtemos o melhor dos dois mundos: propriedades automáticas somente leitura. Isso nos permite simplificar a classe do OP para:
As linhas
Foo = foo
eBar = bar
são válidas apenas no construtor (que atinge o requisito robusto de somente leitura) e o campo de apoio está implícito, em vez de precisar ser explicitamente definido (o que alcança o código mais simples).fonte
Você pode simplesmente se livrar dos levantadores. Eles não fazem nada, confundem os usuários e levam a erros. No entanto, você pode torná-los privados e, assim, livrar-se das variáveis de backup, simplificando seu código:
fonte
public int Foo { get; private set; }
" Essa classe não é mais imutável porque pode mudar a si mesma. Obrigado, no entanto!readonly
palavra-chave é apenas um poka-yoke, ou seja, protege contra a classe que quebra a imutabilidade no futuro; não é necessário alcançar a imutabilidade.Duas soluções
Simples:
Não inclua setters, como observado por David, para objetos imutáveis somente para leitura.
Alternativamente:
Permita que os setters retornem um novo objeto imutável, detalhado em comparação ao anterior, mas fornece estado ao longo do tempo para cada objeto inicializado. Esse design é uma ferramenta muito útil para a segurança e imutabilidade do Thread, que se estende por todas as linguagens imperativas de POO.
Pseudo-código
fábrica estática pública
fonte