Getters e setters implementados automaticamente vs. campos públicos

Eu vejo muito código de exemplo para classs C # que faz isso:

public class Point { public int x { get; set; } public int y { get; set; } } 

Ou, em código antigo, o mesmo com um valor de suporte privado explícito e sem as novas propriedades auto-implementadas:

 public class Point { private int _x; private int _y; public int x { get { return _x; } set { _x = value; } } public int y { get { return _y; } set { _y = value; } } } 

Minha pergunta é por quê. Existe alguma diferença funcional entre fazer o acima e apenas fazer esses membros campos públicos, como abaixo?

 public class Point { public int x; public int y; } 

Para ser claro, eu entendo o valor de getters e setters quando você precisa fazer alguma tradução dos dados subjacentes. Mas nos casos em que você está apenas passando os valores, parece desnecessariamente verboso.

Eu tenho a tendência de concordar (que parece desnecessariamente verboso), embora este tenha sido um problema que nossa equipe ainda não resolveu e, portanto, nossos padrões de codificação ainda insistem em propriedades detalhadas para todas as classs.

Jeff Atwood lidou com isso há alguns anos atrás. O ponto mais importante que ele observou retrospectivamente é que mudar de um campo para uma propriedade é uma quebra de mudança em seu código; qualquer coisa que consome deve ser recompilada para funcionar com a nova interface de class, portanto, se alguma coisa fora de seu controle estiver consumindo sua class, você poderá ter problemas.

Também é muito mais fácil mudar isso para mais tarde:

 public int x { get; private set; } 

Ele encapsula a configuração e o access desses membros. Se daqui a algum tempo um desenvolvedor do código precisar alterar a lógica quando um membro for acessado ou configurado, isso poderá ser feito sem alterar o contrato da class.

A ideia é que, mesmo que a estrutura de dados subjacente precise mudar, a interface pública para a class não precisará ser alterada.

C # pode tratar propriedades e variables ​​de forma diferente às vezes. Por exemplo, você não pode passar propriedades como parâmetros ref ou out . Então, se você precisa mudar a estrutura de dados por algum motivo e você estava usando variables ​​públicas e agora você precisa usar propriedades, sua interface terá que mudar e agora o código que acessa a propriedade x pode não ser mais compilado como era quando era variável x:

 Point pt = new Point(); if(Int32.TryParse(userInput, out pt.x)) { Console.WriteLine("x = {0}", pt.x); Console.WriteLine("x must be a public variable! Otherwise, this won't compile."); } 

Usar as propriedades desde o início evita isso e você pode se sentir à vontade para ajustar a implementação subjacente o quanto for necessário sem quebrar o código do cliente.

Setter e Getter permitem que você adicione uma camada de abstração adicional e, em OOP puro, você deve sempre acessar os objects através da interface que eles estão fornecendo para o mundo externo …

Considere este código, que irá salvá-lo em asp.net e que não seria possível sem o nível de abstração fornecido pelos setters e getters:

 class SomeControl { private string _SomeProperty ; public string SomeProperty { if ( _SomeProperty == null ) return (string)Session [ "SomeProperty" ] ; else return _SomeProperty ; } } 

Como os getters implementados automaticamente levam o mesmo nome para a propriedade e as variables ​​de armazenamento privadas reais. Como você pode mudar isso no futuro? Eu acho que o ponto que está sendo dito é que use o auto implementado ao invés do campo para que você possa mudá-lo no futuro caso precise adicionar lógica ao getter e ao setter.

Por exemplo:

 public string x { get; set; } 

e por exemplo você já usa o xa muitas vezes e você não quer quebrar seu código.

Como você muda o setter automático do getter … por exemplo, para setter você só permite definir um formato de número de telefone válido … como você muda o código para que apenas a class seja alterada?

Minha ideia é adicionar uma nova variável privada e adicionar o mesmo x getter e setter.

 private string _x; public string x { get {return x}; set { if (Datetime.TryParse(value)) { _x = value; } }; } 

É isso que você quer dizer com flexibilidade?

Também deve ser considerado o efeito da mudança para membros públicos quando se trata de encadernação e serialização. Ambos geralmente dependem de propriedades públicas para recuperar e definir valores.

Além disso, você pode colocar pontos de interrupção em getters e setters, mas não pode em campos.

AFAIK a interface CIL gerada é diferente. Se você alterar um membro público para uma propriedade que está alterando, será uma interface pública e precisará reconstruir todos os arquivos que usam essa class. Isso não é necessário se você alterar apenas a implementação dos getters e setters.

Talvez apenas tornar públicos os campos que você poderia levar você a um modelo de domínio mais anêmico .

Atenciosamente

Também é importante notar que você não pode fazer Auto Properties Readonly e você não pode inicializá-los em linha. Ambas são coisas que eu gostaria de ver em uma versão futura do .NET, mas acredito que você não pode fazer nada no .NET 4.0.

As únicas vezes que eu uso um campo de apoio com propriedades nos dias de hoje é quando minha class implementa INotifyPropertyChanged e eu preciso acionar o evento OnPropertyChanged quando uma propriedade é alterada.

Também nessas situações eu defino os campos de apoio diretamente quando os valores são passados ​​de um construtor (não há necessidade de tentar acionar o OnPropertyChangedEvent (que seria NULL neste momento), em qualquer outro lugar eu uso a propriedade em si.

Você nunca sabe se pode precisar de alguma tradução dos dados mais tarde. Você está preparado para isso se esconder seus membros. Os usuários da sua turma não notarão se você adicionar a tradução, pois a interface permanece a mesma.

A maior diferença é que, se você mudar sua estrutura interna, ainda poderá manter os getters e setters como estão, alterando sua lógica interna sem prejudicar os usuários de sua API.

Se você tiver que alterar como obter x e y nesse caso, basta adicionar as propriedades posteriormente. Isso é o que eu acho mais confuso. Se você usar variables ​​de membro público, poderá alterá-lo facilmente para uma propriedade posteriormente e usar variables ​​privadas chamadas _x e _y se precisar armazenar o valor internamente.

Setters e getters são ruins em princípio (eles são um mau cheiro OO – eu vou parar de dizer que eles são um antipadrão porque eles realmente são necessários às vezes).

Não, tecnicamente não há diferença e quando eu realmente quero compartilhar o access a um object nos dias de hoje, ocasionalmente faço com que seja público final em vez de adicionar um getter.

A maneira como setters e getters foram “Vendidos” é que você pode precisar saber que alguém está obtendo um valor ou alterando um – o que só faz sentido com primitivos.

Objetos de objects de propriedades, como DAOs, DTOs e objects de exibição, são excluídos dessa regra, porque eles não são objects em um significado “OO Design” real da palavra Object. (Você não pensa em “Passar Mensagens” para um DAO, é simplesmente uma pilha de pares de atributo / valor).