Campos públicos versus propriedades automáticas

353

Muitas vezes nos dizem que devemos proteger o encapsulamento, criando métodos getter e setter (propriedades em C #) para campos de classe, em vez de expor os campos para o mundo exterior.

Mas há muitas vezes em que um campo está presente apenas para armazenar um valor e não requer nenhum cálculo para obter ou definir. Para estes, todos faríamos este número:

public class Book
{
    private string _title;

    public string Title
    {
          get{ return _title;  }
          set{ _title = value; }
    }
}

Bem, eu tenho uma confissão, eu não aguentava escrever tudo isso (realmente, não era preciso escrever, era preciso olhar para isso), então fui desonesto e usei campos públicos.

Então vem o C # 3.0 e vejo que eles adicionaram propriedades automáticas:

public class Book
{
    public string Title {get; set;} 
}

o que é mais arrumado, e sou grato por isso, mas realmente, o que há de tão diferente do que apenas criar um campo público?

public class Book
{
    public string Title;
}
IJ Kennedy
fonte
6
Eu ter convertido um feild a uma propriedade apenas para que eu pudesse definir um ponto de interrupção na setter
Ian Ringrose
11
Eu tendem a criar qualquer coisa que não seja privada, porque perceber que devo refatorar um campo para uma propriedade levou a uma dor de cabeça desnecessária. Propriedades, campos e métodos. Oh meu! chama a atenção de uma incompatibilidade que me picou no passado.
Steven Wexler
2
O proptrecho de código facilita a criação de propriedades. Basta digitar propentão tab.
Tono Nam

Respostas:

175

Em uma pergunta relacionada que tive há algum tempo, havia um link para uma postagem no blog de Jeff, explicando algumas diferenças.

Propriedades vs. Variáveis ​​Públicas

  • A reflexão funciona de maneira diferente entre variáveis ​​e propriedades; portanto, se você confiar na reflexão, é mais fácil usar todas as propriedades.
  • Você não pode conectar-se a uma variável.
  • Alterar uma variável para uma propriedade é uma mudança de quebra. Por exemplo:

    TryGetTitle(out book.Title); // requires a variable
Michael Stum
fonte
24
"Alterar uma variável para uma propriedade é uma mudança de última hora." É claro que isso se aplica apenas ao escrever uma biblioteca reutilizável, o que a maioria dos desenvolvedores não está fazendo.
29411 Steven
30
Além disso, propriedades, mesmo propriedades automáticas, podem ser virtuais, onde os campos não podem. Portanto, uma classe base pode ter uma implementação simples de campo de apoio, conforme produzida pelo compilador para uma propulsão automática, enquanto as classes derivadas podem executar validação adicional ou outras lógicas / cálculos.
Keiths
28
Também um campo é uma variável e pode ser passado por referência ( refou outpalavra - chave), enquanto uma propriedade é um par de acessadores e não pode ser passado por referência. Por exemplo, bool success = TryGetMyTitle(out myBook.Title);quais usos outfuncionarão com um campo e não funcionarão com uma propriedade. Este é um exemplo claro de por que a mudança de campo para propriedade é uma mudança de última hora!
Jeppe Stig Nielsen
2
@KyleBaran Não, não faz muito sentido, porque uma propriedade é um par de métodos de acessador, não uma variável. Uma coisa comum a se fazer é declarar uma variável local (possivelmente ler a propriedade e colocar seu valor na variável local), passar a variável local como ref/ oute definir a propriedade com o valor que a variável local possui. Mas o método chamado não acessa a propriedade, ele acessa a variável local que você criou lá.
Jeppe Stig Nielsen
5
@theberserker True, embora em C # 6 você possa fazer o public int Foo { get; }que criará uma propriedade automática com um campo de suporte somente leitura.
Michael Stum
83

Ignorando os problemas da API, o que eu acho mais valioso sobre o uso de uma propriedade é a depuração.

O depurador CLR não suporta pontos de interrupção de dados (a maioria dos depuradores nativos suporta). Portanto, não é possível definir um ponto de interrupção na leitura ou gravação de um campo específico de uma classe. Isso é muito limitante em certos cenários de depuração.

Como as propriedades são implementadas como métodos muito finos, é possível definir pontos de interrupção na leitura e gravação de seus valores. Isso lhes dá uma grande vantagem sobre os campos.

JaredPar
fonte
2
Dez anos mais tarde, os pontos de interrupção de dados são aqui, pelo menos para .NET Núcleo :)
Luaan
72

Mudar de um campo para uma propriedade quebra o contrato (por exemplo, exige que todo o código de referência seja recompilado). Portanto, quando você tem um ponto de interação com outras classes - qualquer membro público (e geralmente protegido), deseja planejar um crescimento futuro. Faça isso sempre usando propriedades.

Hoje, não é nada para torná-lo uma propriedade automática, e 3 meses depois da linha você percebe que deseja torná-lo lento e coloca uma verificação nula no getter. Se você usou um campo, esta é uma mudança de recompilação na melhor das hipóteses e impossível na pior das hipóteses, dependendo de quem e o que mais depende de suas montagens.

Rex M
fonte
9
Gostei desta resposta porque não usa as palavras 'reflexão', 'interface' ou 'substituição'. (muito ruim sobre 'contrato')
65

Só porque ninguém mencionou: você não pode definir campos nas interfaces. Portanto, se você precisar implementar uma interface específica que defina propriedades, as propriedades automáticas às vezes são um recurso muito bom.

MartinStettner
fonte
11
Eu diria que se você precisar de uma interface que defina propriedades, deve ser uma classe abstrata. Só porque o c # permite definir propriedades nas interfaces, não significa que você deve usá-las. É um design ruim.
Odys 28/07
8
@odyodyodys - Não sei se concordo que isso é um design ruim. Por favor, explique sua lógica?
Zaid Masud
4
@odyodyodys Concordo com zooone9243: Imp, do ponto de vista do design, não há diferença entre declarar uma propriedade e declarar um par getter / setter (que é uma prática comum para interfaces).
22412 MartinStettner #
22
@ zooone9243, + MartinStettner: Isso foi há 6 meses, eu aprendi muito desde então. Estou retirando :)
Odys
47

Uma enorme diferença que geralmente é ignorada e não é mencionada em nenhuma outra resposta: a substituição . Você pode declarar propriedades virtuais e substituí-las, enquanto não pode fazer o mesmo para os campos públicos de membros.

Zaid Masud
fonte
10

É tudo sobre versionamento e estabilidade da API. Não há diferença na versão 1 - mas mais tarde, se você decidir tornar essa propriedade uma propriedade com algum tipo de verificação de erro na versão 2, não precisará alterar sua API - nenhuma alteração de código, em qualquer lugar, exceto a definição da propriedade.

Reed Copsey
fonte
10

Outra vantagem das propriedades implementadas automaticamente sobre os campos públicos é que você pode tornar os acessadores definidos privados ou protegidos, fornecendo à classe de objetos onde foi definido um controle melhor do que a dos campos públicos.

Arnaldo
fonte
8

Não há nada errado em criar um campo public. Mas lembre-se de criar getter/settercom privatecampos não é encapsulamento. IMO: Se você não se importa com outros recursos de a Property, é melhor fazê-lo public.

fastcodejava
fonte
1

Se você decidir posteriormente verificar se o título é exclusivo, comparando-se com uma coleção ou um banco de dados, poderá fazer isso na propriedade sem alterar nenhum código que dependa disso.

Se você optar por apenas um atributo público, terá menos flexibilidade.

A flexibilidade extra sem quebrar o contrato é o mais importante para mim sobre o uso de propriedades e, até que eu realmente precise da flexibilidade, a geração automática faz mais sentido.

James Black
fonte
0

Uma coisa que acho muito útil, além de todos os motivos de código e teste, é que, se for uma propriedade versus um campo, o IDE do Visual Studio mostra as referências para uma propriedade, mas não para um campo.

TrtlBoy
fonte
0

Meu pov depois fiz algumas pesquisas

  1. Validação.
  2. Permite substituir o acessador para alterar o comportamento de uma propriedade.
  3. Objetivo de depuração. Poderemos saber quando e o que a propriedade muda, definindo um ponto de interrupção no acessador.
  4. Podemos ter um campo somente conjunto. Por exemplo, set público () e get privado (). Isso não é possível com o campo público.

Realmente nos dá mais possibilidade e extensibilidade.

KunYu Tsai
fonte