Diferença entre propriedade e campo no C # 3.0+

140

Sei que parece ser uma duplicata de Qual é a diferença entre um campo e uma propriedade em c #? mas minha pergunta tem uma pequena diferença (do meu ponto de vista):

Quando eu souber disso

  • Não usarei minha classe com "técnicas que funcionam apenas em propriedades" e
  • Não usarei código de validação no getter / setter.

Existe alguma diferença (exceto as de estilo / desenvolvimento futuro), como algum tipo de controle na configuração da propriedade?

Existe alguma diferença adicional entre:

public string MyString { get; set; }

e

public string myString;

(Estou ciente de que a primeira versão requer C # 3.0 ou superior e que o compilador cria os campos particulares.)

p4bl0
fonte

Respostas:

117

Encapsulamento.

Na segunda instância, você acabou de definir uma variável; na primeira, há um getter / setter em torno da variável. Portanto, se você decidir validar a variável posteriormente - será muito mais fácil.

Além disso, eles aparecem de maneira diferente no Intellisense :)

Editar: pergunta atualizada da atualização para OPs - se você deseja ignorar as outras sugestões aqui, o outro motivo é que simplesmente não é um bom design de OO. E se você não tiver um bom motivo para fazê-lo, sempre escolha uma propriedade sobre uma variável / campo público.

Mark Ingram
fonte
9
Por que será mais fácil? O que me impede de transformar um campo em uma propriedade e adicionar um campo de apoio privado? Como isso afeta o código de chamada?
Serge Wautier
30
@ Emerge - Afeta o código já compilado. Por exemplo, se você estiver desenvolvendo uma biblioteca usada por vários aplicativos, alterar um campo para uma propriedade nessa biblioteca exigiria uma recompilação de cada aplicativo. Se fosse uma propriedade, você poderia atualizar a propriedade sem se preocupar.
Dustin Campbell
Eu concordo totalmente com você, eu sempre uso propriedades. Eu estava apenas curioso sobre a diferença possível
p4bl0
24
Se o código consumindo é sempre recompilados ao mesmo tempo que a classe afetada (então qualquer coisa privada ou interna sem internos visíveis é 100% seguro), em seguida, tornando-se um campo é perfeitamente OK
ShuggyCoUk
1
wow Shuggy, seu comentário é exatamente a resposta que eu estava procurando!
P4bl0 17/03/09
160

Campos e propriedades têm a mesma aparência, mas não são. Propriedades são métodos e, como tal, existem certas coisas que não são suportadas por propriedades e outras que podem acontecer com propriedades, mas nunca no caso de campos.

Aqui está uma lista de diferenças:

  • Os campos podem ser usados ​​como entrada para out/refargumentos. Propriedades não podem.
  • Um campo sempre produzirá o mesmo resultado quando chamado várias vezes (se deixarmos de fora os problemas com vários encadeamentos). Uma propriedade como DateTime.Nownem sempre é igual a si mesma.
  • As propriedades podem gerar exceções - os campos nunca farão isso.
  • As propriedades podem ter efeitos colaterais ou levar muito tempo para serem executadas. Os campos não têm efeitos colaterais e sempre serão tão rápidos quanto o esperado para o tipo especificado.
  • As propriedades suportam acessibilidade diferente para getters / setters - os campos não (mas os campos podem ser criados readonly)
  • Ao usar a reflexão, as propriedades e os campos são tratados como diferentes e, MemberTypesportanto, estão localizados de maneira diferente ( GetFieldsvs GetPropertiespor exemplo)
  • O compilador JIT pode tratar o acesso à propriedade de maneira muito diferente em comparação ao acesso ao campo. No entanto, ele pode ser compilado em código nativo idêntico, mas o escopo da diferença existe.
Brian Rasmussen
fonte
11
Observe, no entanto, que vários desses pontos não devem ter diferenças se forem utilizadas boas práticas. Ou seja, as propriedades realmente nunca devem ter efeitos colaterais, nem levar muito tempo para serem executadas.
Noldorin
15
@Oldoldin: Eu concordo, mas infelizmente deveria ser a palavra-chave aqui. Com campos esse comportamento é garantido. Não estou dizendo que você deve usar campos, mas é importante estar ciente das diferenças semânticas.
Brian Rasmussen
4
Sim, é justo. Programadores iniciantes não têm a menor idéia sobre essas coisas muitas vezes, infelizmente ...
Noldorin
2
Além disso, os campos podem ter um inicializador de campos, enquanto as propriedades precisam ser inicializadas em um construtor.
Dio F
3
Eu sinto que essa resposta é melhor do que a resposta aceita. Estou começando a pensar que a maneira "aceitável" de sempre preferir propriedades sobre os campos é pensar mal. Se você precisar lidar apenas com dados, use um campo Se você precisar aplicar funcionalidade aos dados, use um método Como as propriedades podem ter efeitos colaterais que você não conhece (especialmente se você não projetou a biblioteca e possui pouca documentação), elas parecem contra-intuitivas para mim na maioria dos casos.
David Peterson
41

Algumas diferenças rápidas e óbvias

  1. Uma propriedade pode ter palavras-chave de acessador.

    public string MyString { get; private set; }
  2. Uma propriedade pode ser substituída por descendentes.

    public virtual string MyString { get; protected set; }
Dustin Campbell
fonte
1
mmh .. nr 2 é interessante .. eu não pensei nisso
p4bl0
14

A diferença fundamental é que um campo é uma posição na memória em que os dados do tipo especificado são armazenados. Uma propriedade representa uma ou duas unidades de código que são executadas para recuperar ou definir um valor do tipo especificado. O uso desses métodos de acesso é oculto sintaticamente, usando um membro que parece se comportar como um campo (pois pode aparecer nos dois lados de uma operação de atribuição).

AnthonyWJones
fonte
11

Os acessadores são mais do que campos. Outros já apontaram várias diferenças importantes, e vou acrescentar mais uma.

Propriedades participam de classes de interface. Por exemplo:

interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

Essa interface pode ser satisfeita de várias maneiras. Por exemplo:

class Person: IPerson
{
    private string _name;
    public string FirstName
    {
        get
        {
            return _name ?? string.Empty;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException("value");
            _name = value;
        }
    }
    ...
}

Nesta implementação, estamos protegendo a Personclasse de entrar em um estado inválido, bem como o chamador de sair nulo da propriedade não atribuída.

Mas poderíamos levar o design ainda mais longe. Por exemplo, a interface pode não lidar com o configurador. É bastante legítimo dizer que os consumidores de IPersoninterface estão interessados ​​apenas em obter a propriedade, não em defini-la:

interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}

A implementação anterior da Personclasse satisfaz essa interface. O fato de permitir que o chamador também defina as propriedades não faz sentido do ponto de vista dos consumidores (que consomem IPerson). Funcionalidades adicionais da implementação concreta são levadas em consideração por, por exemplo, o construtor:

class PersonBuilder: IPersonBuilder
{
    IPerson BuildPerson(IContext context)
    {

        Person person = new Person();

        person.FirstName = context.GetFirstName();
        person.LastName = context.GetLastName();

        return person;

    }
}

...

void Consumer(IPersonBuilder builder, IContext context)
{
    IPerson person = builder.BuildPerson(context);
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

Nesse código, o consumidor não conhece os criadores de propriedades - não é da sua conta saber sobre isso. O consumidor precisa apenas de getters, e ele recebe da interface, ou seja, do contrato.

Outra implementação completamente válida IPersonseria uma classe de pessoa imutável e uma fábrica de pessoa correspondente:

class Person: IPerson
{
    public Person(string firstName, string lastName)
    {

        if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
            throw new System.ArgumentException();

        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

}

...

class PersonFactory: IPersonFactory
{
    public IPerson CreatePerson(string firstName, string lastName)
    {
        return new Person(firstName, lastName);
    }
}
...
void Consumer(IPersonFactory factory)
{
    IPerson person = factory.CreatePerson("John", "Doe");
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

Neste código de amostra, o consumidor mais uma vez não tem conhecimento de preencher as propriedades. O consumidor lida apenas com getters e a implementação concreta (e a lógica de negócios por trás dele, como testar se o nome está vazio) é deixada para as classes especializadas - construtores e fábricas. Todas essas operações são totalmente impossíveis com campos.

Zoran Horvat
fonte
7

O primeiro:

public string MyString {get; set; }

é uma propriedade; o segundo ( public string MyString) indica um campo.

A diferença é que certas técnicas (ligação de dados do ASP.NET para instâncias) funcionam apenas em propriedades e não em campos. O mesmo vale para serialização de XML: apenas propriedades são serializadas, campos não são serializados.

Frederik Gheysels
fonte
8
Errado. Serialização XML serializa campos públicos.
Serge Wautier
2
Talvez. Mas quando você cria uma fonte de dados de objeto a partir de uma classe, você só usa as propriedades, não os campos. (A menos que eu tenha feito algo errado: P)
Svish
Bom é SECO;), mas eu escrevo mais uma vez, gosto de um forte papel da propriedade na linguagem C #. É muito melhor implementado do que em Java (conseqüentemente desde o início) Muitas, talvez todas as soluções .net funcionem apenas em propriedades. WPF, ASPX e mais.
Jacek Cz
3

Propriedades e campos podem, em muitos casos, parecer semelhantes, mas não são. Existem limitações para propriedades que não existem para campos e vice-versa.

Como outros já mencionaram. Você pode tornar uma propriedade somente leitura ou somente gravação, tornando seu acessador privado. Você não pode fazer isso com um campo. As propriedades também podem ser virtuais, enquanto os campos não.

Pense nas propriedades como um açúcar sintático para as funções getXXX () / setXXX (). É assim que eles são implementados nos bastidores.

Erik Funkenbusch
fonte
1

Há outra diferença importante entre campos e propriedades.

Ao usar o WPF, você pode vincular apenas a propriedades públicas. A ligação a um campo público não funcionará. Isso é verdade mesmo quando não está implementando INotifyPropertyChanged(mesmo que você sempre deva).

BradleyDotNET
fonte
Bom é SECO;), mas eu escrevo mais uma vez, gosto de um forte papel da propriedade na linguagem C #. É muito melhor implementado do que em Java (conseqüentemente desde o início) Muitas, talvez todas as soluções .net funcionem apenas em propriedades. WPF, ASPX e mais.
Jacek Cz
1

Entre outras respostas e exemplos, acho que este exemplo é útil em algumas situações.

Por exemplo, digamos que você tenha o seguinte:OnChange property

public Action OnChange { get; set; }

Se você quiser usar delegados, precisará alterá-lo OnChange para field:

public event Action OnChange = delegate {};

Em tal situação, protegemos nosso campo de acesso ou modificação indesejados.

maytham-ɯɐɥʇʎɐɯ
fonte
0

Você deve sempre usar propriedades em vez de campos para quaisquer campos públicos. Isso garante que sua biblioteca tenha a capacidade de implementar o encapsulamento para qualquer campo, se necessário no futuro, sem quebrar os códigos existentes. Se você substituir os campos por propriedades nas bibliotecas existentes, todas as módulos dependentes que usam sua biblioteca também precisam ser reconstruídos.

user1849310
fonte
"sempre" é um direito à palavra difícil. Em C # (melhor que em Java), a propriedade tem uma posição forte, é (provavelmente sem exceção) o principal / método de "ligação" em ASP, WPF e outros. Mas, mesmo assim eu posso imaginar projeto com o campo não sendo propriedade tem sentido (às vezes)
Jacek Cz