Qual é a diferença entre um campo e uma propriedade?

1130

Em C #, o que diferencia um campo de uma propriedade e quando um campo deve ser usado em vez de uma propriedade?

anônimo
fonte
32
A Microsoft responde diretamente a essa pergunta (para todos os idiomas do .NET) como parte das Diretrizes de design para membros . Para detalhes, consulte os artigos Design de propriedades e Design de campos . Observe que há uma distinção entre membros da instância e membros estáticos .
DavidRR

Respostas:

979

Propriedades expõem campos. Os campos devem (quase sempre) ser mantidos em sigilo para uma classe e acessados ​​por meio de propriedades get e set. As propriedades fornecem um nível de abstração que permite alterar os campos sem afetar a maneira externa como eles são acessados ​​pelas coisas que usam sua classe.

public class MyClass
{
    // this is a field.  It is private to your class and stores the actual data.
    private string _myField;

    // this is a property. When accessed it uses the underlying field,
    // but only exposes the contract, which will not be affected by the underlying field
    public string MyProperty
    {
        get
        {
            return _myField;
        }
        set
        {
            _myField = value;
        }
    }

    // This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
    // used to generate a private field for you
    public int AnotherProperty{get;set;} 
}

O @Kent ressalta que as Propriedades não precisam encapsular os campos, elas podem fazer um cálculo em outros campos ou servir a outros propósitos.

O @GSS salienta que você também pode executar outra lógica, como validação, quando uma propriedade é acessada, outro recurso útil.

Cory
fonte
185
Vale ressaltar que as propriedades não são necessárias para encapsular os campos. Não poderia haver campo atrás da propriedade. Pode ser um cálculo ou retornar uma constante ou qualquer outra coisa.
21730 Kent Kentogaoga
9
"embora não afetem a maneira externa, eles são acessados ​​pelas coisas que usam sua classe." perdoe-me se estou entendendo incorretamente, mas por que a necessidade de modificadores de acesso na frente de propriedades, se o campo por trás dele parece lidar com isso? ou seja, por que tornar uma propriedade diferente de pública?
Chucky
18
Sua resposta foi um pouco antes das edições e dos comentários incorretos com votos curiosos. Uma propriedade deve sempre encapsular um ou mais campos e nunca deve fazer nenhum trabalho pesado ou validação. Se você precisar de uma propriedade como Nome de Usuário ou Senha para validação, altere seu tipo de cadeias para Objetos de Valor . Existe um contrato tácito entre o criador da classe e o consumidor. Os campos mantêm o estado, as Propriedades expõem o estado usando um ou mais campos, os Vazios mudam de estado (trabalho pesado) e as Funções realizam consultas (trabalho pesado).
Suamere 6/11/15
6
@jpaugh Se eu sou um consumidor de classe, sigo os contratos estabelecidos pelo criador da classe. Se uma propriedade for string, meu contrato é: atribua quaisquer caracteres até ~ 2bil. Se for uma propriedade DateTime, meu contrato é: atribua quaisquer números dentro dos limites de DateTime, que eu possa procurar. Se o criador adicionar restrições aos levantadores, essas restrições não serão comunicadas. Mas se, em vez disso, o criador alterar o tipo de stringpara Surname, a nova classe Sobrenome comunicará as restrições e a propriedade public Surname LastNamenão terá validação de setter. Além disso, Surnameé reutilizável.
Suamere
4
E como Surname, no meu exemplo, é reutilizável, você não precisa se preocupar em copiar / colar essas validações em um configurador de propriedades para outros locais no código. Também não é de admirar se a validação de um Sobrenome está em vários lugares, se você alguma vez fizer alterações nas regras de negócios para Apelidos. Confira no link eu postei sobre Valor Objects
Suamere
261

Os princípios de programação orientada a objetos dizem que, o funcionamento interno de uma classe deve estar oculto do mundo exterior. Se você expõe um campo, está essencialmente expondo a implementação interna da classe. Portanto, agrupamos campos com Propriedades (ou métodos no caso de Java) para nos permitir alterar a implementação sem quebrar o código, dependendo de nós. Ver como podemos colocar lógica na Propriedade também nos permite executar a lógica de validação, etc., se precisarmos. O C # 3 tem a noção possivelmente confusa de autopropriedade. Isso nos permite simplesmente definir a Propriedade e o compilador C # 3 irá gerar o campo privado para nós.

public class Person
{
   private string _name;

   public string Name
   {
      get
      {
         return _name;
      }
      set
      {
         _name = value;
      }
   }
   public int Age{get;set;} //AutoProperty generates private field for us
}
danswain
fonte
89
+1 por mencionar propriedades automáticas - acho que isso é algo que muitas das respostas aqui (e em outros lugares) esqueceram de trazer. Sem essa explicação, ainda pode ser bem difícil entender o que public int myVar { get; set; }realmente significa (e presumo que seja esse o motivo). pelo menos 50% dos acessos que essa pergunta recebe).
Priidu Neemre
7
+1 também por mencionar auto e por mencionar como ele funciona ("A AutoProperty gera um campo privado para nós") Essa foi a resposta que eu estava procurando para uma pergunta que eu tinha. Ao pesquisar, não vi na página do MSDN sobre eles nenhuma indicação de que um campo privado foi criado e estava causando confusão. Eu acho que é isso que isso significa? "Atributos são permitidos em propriedades implementadas automaticamente, mas obviamente não nos campos de apoio, pois eles não são acessíveis a partir do seu código-fonte. Se você deve usar um atributo no campo de apoio de uma propriedade, basta criar uma propriedade regular." mas não tinha certeza.
Nyra
3
Observe que o exemplo dado não encapsula o agachamento. Essa propriedade fornece 100% de acesso total ao campo privado, portanto, isso não é orientado a objetos. Você também pode ter um campo público neste caso. Concedido, ajuda (marginalmente) a refatorar o código no futuro, mas qualquer IDE que valha a pena pode transformar um campo em uma propriedade com apenas algumas teclas. A resposta pode estar tecnicamente correta sobre como as propriedades funcionam, mas não fornece uma boa "explicação OOP" para seus usos.
Sara
2
@kai Concordo que a resposta simplificou demais as coisas e não está mostrando todo o poder de uma propriedade automática, mas discordo que isso não seja orientado a objetos. Você pode querer verificar a diferença entre campos e propriedades . Os campos não podem ser virtuais e virtualfazem parte da programação orientada a objetos.
Gobe
Concedido, há alguma diferença funcional. Eu não chamaria virtualOOP em si, no entanto. É uma ferramenta que permite o polimorfismo, que é uma das principais ferramentas que HABITA OOP. Porém, não é OOP por si só, e não há nada inerentemente OOP em uma propriedade pública pública. Também não contaria coisas como reflexão ou ligação de dados relacionadas ao OOP. Normalmente, eu não seria tão pedante quanto a isso, mas a resposta mencionou especificamente os princípios de OO como a força motriz por trás do exemplo de código, e não concordo com isso.
Sara
164

Uma diferença importante é que as interfaces podem ter propriedades, mas não campos. Isso, para mim, sublinha que as propriedades devem ser usadas para definir a interface pública de uma classe, enquanto os campos devem ser usados ​​no funcionamento interno privado de uma classe. Como regra, raramente crio campos públicos e da mesma forma raramente crio propriedades não públicas.

Hans Løken
fonte
98

Vou dar alguns exemplos de como usar propriedades que podem fazer as engrenagens girarem:

  • Inicialização lenta : se você tem uma propriedade de um objeto que é caro para carregar, mas não é acessado tanto em execuções normais do código, pode atrasar o carregamento por meio da propriedade Dessa forma, ele fica parado, mas na primeira vez em que outro módulo tenta chamar essa propriedade, ele verifica se o campo subjacente é nulo - se for, ele segue em frente e carrega, desconhecido para o módulo de chamada. Isso pode acelerar bastante a inicialização do objeto.
  • Dirty Tracking: sobre o qual aprendi na minha própria pergunta aqui no StackOverflow. Quando tenho muitos objetos cujos valores podem ter sido alterados durante uma execução, posso usar a propriedade para rastrear se eles precisam ser salvos no banco de dados ou não. Se nenhuma propriedade de um objeto foi alterada, o sinalizador IsDirty não será acionado e, portanto, a funcionalidade de salvamento o ignorará ao decidir o que precisa voltar ao banco de dados.
Chris
fonte
1
Uma pergunta sobre rastreamento sujo: e se eu pudesse alterar o campo diretamente - não sei se isso pode ser feito, eu poderia dizer: "o objeto não precisa ser salvo se não houver um único CAMPO de um objeto alterado" assim, o rastreamento sujo não faria diferença, estou perdendo alguma coisa?
Sites
2
@juanpastas: A vantagem das propriedades em relação ao rastreamento sujo é que, se os configuradores de propriedades definirem um sinalizador "sujo", no cenário em que o código do sinalizador não está definido, não será necessário inspecionar os valores de nenhuma propriedade para ver se eles podem ter mudado. Por outro lado, se um objeto expõe seus atributos como campos, o conteúdo de todos os campos deve ser comparado com o valor anterior (o que não apenas acrescenta tempo para a comparação, mas também significa que o código deve ter o valor anterior).
Supercat
Essas são boas. Também permite acionar métodos (como eventos) ou registrar quando o valor é definido ou lido.
Coloboxp # 24/16
54

Usando Propriedades, você pode gerar um evento quando o valor da propriedade é alterado (também conhecido como PropertyChangedEvent) ou antes que o valor seja alterado para suportar o cancelamento.

Isso não é possível com (acesso direto a) campos.

public class Person {
 private string _name;

 public event EventHandler NameChanging;     
 public event EventHandler NameChanged;

 public string Name{
  get
  {
     return _name;
  }
  set
  {
     OnNameChanging();
     _name = value;
     OnNameChanged();
  }
 }

 private void OnNameChanging(){       
     NameChanging?.Invoke(this,EventArgs.Empty);       
 }

 private void OnNameChanged(){
     NameChanged?.Invoke(this,EventArgs.Empty);
 }
}
Jehof
fonte
3
Demorei muito para encontrar isso. Este é um MVVM . Obrigado ! :)
46

Como muitos deles explicaram com prós e contras técnicos de Propertiese Field, é hora de entrar em exemplos em tempo real.

1. Propriedades permite definir o nível de acesso somente leitura

Considere o caso de dataTable.Rows.Counte dataTable.Columns[i].Caption. Eles vêm da classe DataTablee ambos são públicos para nós. A diferença no nível de acesso a eles é que não podemos definir valor, dataTable.Rows.Countmas podemos ler e escrever dataTable.Columns[i].Caption. Isso é possível Field? Não!!! Isso pode ser feito Propertiesapenas.

public class DataTable
{
    public class Rows
    {       
       private string _count;        

       // This Count will be accessable to us but have used only "get" ie, readonly
       public int Count
       {
           get
           {
              return _count;
           }       
       }
    } 

    public class Columns
    {
        private string _caption;        

        // Used both "get" and "set" ie, readable and writable
        public string Caption
        {
           get
           {
              return _caption;
           }
           set
           {
              _caption = value;
           }
       }       
    } 
}

2. Propriedades no PropertyGrid

Você pode ter trabalhado Buttonno Visual Studio. Suas propriedades são mostradas da PropertyGridmesma forma Text, Nameetc. Quando arrastamos e soltamos um botão, e quando clicamos nas propriedades, ele automaticamente encontra a classe Buttone os filtros Propertiese mostra isso em PropertyGrid(onde PropertyGridnão será exibido Fieldmesmo que seja público).

public class Button
{
    private string _text;        
    private string _name;
    private string _someProperty;

    public string Text
    {
        get
        {
           return _text;
        }
        set
        {
           _text = value;
        }
   } 

   public string Name
   {
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   } 

   [Browsable(false)]
   public string SomeProperty
   {
        get
        {
           return _someProperty;
        }
        set
        {
           _someProperty= value;
        }
   } 

Em PropertyGrid, as propriedades Namee Textserão mostradas, mas não SomeProperty. Por quê??? Porque Propriedades podem aceitar Atributos . Não aparece no caso em que [Browsable(false)]é falso.

3. Pode executar instruções dentro de Propriedades

public class Rows
{       
    private string _count;        


    public int Count
    {
        get
        {
           return CalculateNoOfRows();
        }  
    } 

    public int CalculateNoOfRows()
    {
         // Calculation here and finally set the value to _count
         return _count;
    }
}

4. Somente propriedades podem ser usadas na fonte de ligação

Fonte de ligação nos ajuda a diminuir o número de linhas de código. Fieldsnão são aceitos por BindingSource. Deveríamos usar Propertiespara isso.

5. modo de depuração

Considere que estamos usando Fieldpara manter um valor. Em algum momento, precisamos depurar e verificar onde o valor está ficando nulo para esse campo. Será difícil fazer onde o número de linhas de código é superior a 1000. Nessas situações, podemos usar Propertye definir o modo de depuração dentro Property.

   public string Name
   {
        // Can set debug mode inside get or set
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   }
Sarath Avanavu
fonte
Esses são fatos interessantes, mas você está perdendo a filosofia dos campos e das propriedades.
David Ferenczy Rogožan
O que você quer dizer com FILISOFIA ? @Dawid Ferenczy
Sarath Avanavu
Veja, por exemplo, resposta marcada. Mas você notou que você está apenas proporcionando um exemplos de uso, desde diferença entre campos e propriedades já foi descrito, por isso esqueceu meu comentário, por favor :)
David Ferenczy Rogožan
2
Leia minha primeira frase na minha resposta. Eu disse especificamente que não vou repetir tudo novamente aqui. Isso não faz sentido!!! As pessoas analisarão primeiro a descrição, depois os exemplos. A resposta marcada fornece uma boa descrição, mas adicionei alguns cenários e exemplos em tempo real que fazem sentido. Por favor, certifique-se de pensar do ponto de vista do leitor antes de comentar @Dawid Ferenczy
Sarath Avanavu
1
Eu li, mas você não leu meu comentário anterior, obviamente: " Mas você percebeu que está apenas fornecendo exemplos de uso, já que a diferença entre campos e propriedades já foi descrita, então esqueci meu comentário, por favor :) " .
David Ferenczy Rogožan
32

DIFERENÇAS - USOS (quando e por que)

Um campo é uma variável declarada diretamente em uma classe ou estrutura. Uma classe ou estrutura pode ter campos de instância ou campos estáticos ou ambos. Geralmente, você deve usar campos apenas para variáveis ​​que tenham acessibilidade privada ou protegida . Os dados que sua classe expõe ao código do cliente devem ser fornecidos por meio de métodos, propriedades e indexadores. Ao usar essas construções para acesso indireto a campos internos, você pode proteger contra valores de entrada inválidos.

Uma propriedade é um membro que fornece um mecanismo flexível para ler, gravar ou calcular o valor de um campo particular. As propriedades podem ser usadas como se fossem membros de dados públicos, mas na verdade são métodos especiais chamados acessadores . Isso permite que os dados sejam acessados ​​com facilidade e ainda ajuda a promover a segurança e a flexibilidade dos métodos . As propriedades permitem que uma classe exponha uma maneira pública de obter e definir valores, enquanto oculta o código de implementação ou verificação. Um acessador de propriedade get é usado para retornar o valor da propriedade e um acessador definido é usado para atribuir um novo valor.

makiSTB
fonte
Esta é uma resposta incrível, realmente me ajudou a entender isso.
21818 Steve Bauman
14

As propriedades têm a principal vantagem de permitir que você altere a maneira como os dados em um objeto são acessados ​​sem interromper sua interface pública. Por exemplo, se você precisar adicionar validação extra ou alterar um campo armazenado em um calculado, poderá fazê-lo facilmente se inicialmente expôs o campo como uma propriedade. Se você acabou de expor um campo diretamente, precisará alterar a interface pública da sua classe para adicionar a nova funcionalidade. Essa alteração quebraria os clientes existentes, exigindo que eles fossem recompilados antes que eles pudessem usar a nova versão do seu código.

Se você escrever uma biblioteca de classes projetada para amplo consumo (como o .NET Framework, que é usado por milhões de pessoas), isso pode ser um problema. No entanto, se você estiver escrevendo uma classe usada internamente em uma pequena base de código (digamos <= 50 K linhas), isso realmente não é grande coisa, porque ninguém seria afetado adversamente por suas alterações. Nesse caso, realmente se resume a preferência pessoal.

Scott Wisniewski
fonte
11

As propriedades suportam acesso assimétrico, ou seja, você pode ter um getter e um setter ou apenas um dos dois. Da mesma forma, as propriedades suportam acessibilidade individual para getter / setter. Os campos são sempre simétricos, ou seja, você sempre pode obter e definir o valor. Exceção a isso são campos somente leitura que obviamente não podem ser definidos após a inicialização.

As propriedades podem ser executadas por um período muito longo, ter efeitos colaterais e até gerar exceções. Os campos são rápidos, sem efeitos colaterais e nunca lançam exceções. Devido aos efeitos colaterais, uma propriedade pode retornar um valor diferente para cada chamada (como pode ser o caso de DateTime.Now, ou seja, DateTime.Now nem sempre é igual a DateTime.Now). Os campos sempre retornam o mesmo valor.

Os campos podem ser usados ​​para parâmetros de saída / referência, as propriedades não. As propriedades suportam lógica adicional - isso pode ser usado para implementar o carregamento lento entre outras coisas.

As propriedades suportam um nível de abstração encapsulando o que significa obter / definir o valor.

Use propriedades na maioria dos casos, mas tente evitar efeitos colaterais.

Brian Rasmussen
fonte
Os campos podem ter todos os problemas de custo das propriedades quando o tipo de dados do campo é um objeto com uma sobrecarga do operador de conversão - é uma pegada sutil.
Andy Dent
1
Propriedades nunca devem ter efeitos colaterais. Até o depurador assume que pode avaliá-los com segurança.
Craig Gidney
@ Strilanc: Concordo completamente, no entanto, esse nem sempre é o caso. Quanto ao depurador, há muitos problemas com o FuncEval, se é disso que você está falando.
Brian Rasmussen
11

No fundo, uma propriedade é compilada em métodos. Portanto, uma Namepropriedade é compilada em get_Name()e set_Name(string value). Você pode ver isso se você estudar o código compilado. Portanto, há uma sobrecarga (muito) pequena de desempenho ao usá-los. Normalmente, você sempre usará uma propriedade se expor um campo para o exterior e frequentemente a usará internamente, se precisar validar o valor.

Rune Grimstad
fonte
7

Quando você deseja que sua variável privada (campo) seja acessível ao objeto de sua classe de outras classes, é necessário criar propriedades para essas variáveis.

por exemplo, se eu tiver variáveis ​​nomeadas como "id" e "name", que são privadas, mas pode haver uma situação em que essa variável seja necessária para a operação de leitura / gravação fora da classe. Nessa situação, a propriedade pode me ajudar a obter essa variável para leitura / gravação, dependendo do get / set definido para a propriedade. Uma propriedade pode ser somente leitura / gravação / gravação / leitura.

aqui está a demo

class Employee
{
    // Private Fields for Employee
    private int id;
    private string name;

    //Property for id variable/field
    public int EmployeeId
    {
       get
       {
          return id;
       }
       set
       {
          id = value;
       }
    }

    //Property for name variable/field
    public string EmployeeName
    {
       get
       {
          return name;
       }
       set
       {
          name = value;
       }
   }
}

class MyMain
{
    public static void Main(string [] args)
    {
       Employee aEmployee = new Employee();
       aEmployee.EmployeeId = 101;
       aEmployee.EmployeeName = "Sundaran S";
    }
}
Petryanu
fonte
6

A segunda pergunta aqui, "quando um campo deve ser usado em vez de uma propriedade?", É abordada apenas brevemente nessa outra resposta e meio que também , mas sem muitos detalhes.

Em geral, todas as outras respostas são claras sobre o bom design: prefira expor propriedades ao invés de expor campos. Enquanto você provavelmente não vai se veja dizendo "uau, imagine como as coisas seriam piores se eu tivesse transformado esse campo em vez de uma propriedade", é muito mais raro pensar em uma situação em que você diria "uau, graças a Deus eu usei um campo aqui em vez de uma propriedade ".

Mas há uma vantagem que os campos têm sobre as propriedades, e essa é a capacidade delas de serem usadas como parâmetros "ref" / "out". Suponha que você tenha um método com a seguinte assinatura:

public void TransformPoint(ref double x, ref double y);

e suponha que você queira usar esse método para transformar uma matriz criada assim:

System.Windows.Point[] points = new Point[1000000];
Initialize(points);

Aqui está a maneira mais rápida de fazer isso, já que X e Y são propriedades:

for (int i = 0; i < points.Length; i++)
{
    double x = points[i].X;
    double y = points[i].Y;
    TransformPoint(ref x, ref y);
    points[i].X = x;
    points[i].Y = y;
}

E isso vai ser muito bom! A menos que você tenha medidas que provem o contrário, não há motivo para dar um fedor. Mas acredito que não é tecnicamente garantido que seja tão rápido quanto isso:

internal struct MyPoint
{
    internal double X;
    internal double Y;
}

// ...

MyPoint[] points = new MyPoint[1000000];
Initialize(points);

// ...

for (int i = 0; i < points.Length; i++)
{
    TransformPoint(ref points[i].X, ref points[i].Y);
}

Fazendo algumas medições sozinho, a versão com campos leva cerca de 61% do tempo com a versão com propriedades (.NET 4.6, Windows 7, x64, modo de liberação, sem depurador conectado). Quanto mais caro o TransformPointmétodo fica, menos pronunciada é a diferença. Para repetir isso, execute com a primeira linha comentada e com ela não comentada.

Mesmo se não houver benefícios de desempenho para os itens acima, há outros locais em que a capacidade de usar parâmetros ref e out pode ser benéfica, como ao chamar a família de métodos Interlocked ou Volatile . Nota: Caso isso seja novo para você, o Volatile é basicamente uma maneira de obter o mesmo comportamento fornecido pela volatilepalavra - chave. Assim volatile, ele não resolve magicamente todos os problemas de segurança de threads, como o próprio nome sugere.

Definitivamente, não quero parecer que estou defendendo que você diga "ah, devo começar a expor campos em vez de propriedades". O ponto é que, se você precisar usar esses membros regularmente em chamadas que usam parâmetros "ref" ou "out", especialmente em algo que pode ser um tipo de valor simples, é improvável que você precise de algum elemento de valor agregado das propriedades, um argumento pode ser feito.

Joe Amenta
fonte
6

Embora os campos e as propriedades pareçam semelhantes, são dois elementos de linguagem completamente diferentes.

  1. Os campos são o único mecanismo de armazenamento de dados no nível da classe. Os campos são conceitualmente variáveis ​​no escopo da classe. Se você deseja armazenar alguns dados em instâncias de suas classes (objetos), precisará usar campos. Não há outra escolha. As propriedades não podem armazenar dados, embora possa parecer que eles são capazes de fazê-lo. Veja abaixo.

  2. As propriedades, por outro lado, nunca armazenam dados. Eles são apenas os pares de métodos (obter e definir) que podem ser chamados sintaticamente de maneira semelhante aos campos e, na maioria dos casos, acessam campos (para leitura ou gravação), que é a fonte de alguma confusão. Mas como os métodos de propriedade são (com algumas limitações, como protótipo fixo) métodos C # regulares, eles podem fazer o que os métodos regulares podem fazer. Isso significa que eles podem ter 1000 linhas de código, podem gerar exceções, chamar outros métodos, podem ser virtuais, abstratos ou substituídos. O que torna as propriedades especiais é o fato de o compilador C # armazenar alguns metadados extras em assemblies que podem ser usados ​​para procurar propriedades específicas - recurso amplamente usado.

Os métodos de propriedade Get e set possuem os seguintes protótipos.

PROPERTY_TYPE get();

void set(PROPERTY_TYPE value);

Portanto, significa que as propriedades podem ser 'emuladas' definindo um campo e 2 métodos correspondentes.

class PropertyEmulation
{
    private string MSomeValue;

    public string GetSomeValue()
    {
        return(MSomeValue);
    }

    public void SetSomeValue(string value)
    {
        MSomeValue=value;
    }
}

Essa emulação de propriedade é típica para linguagens de programação que não suportam propriedades - como C ++ padrão. Em C #, você sempre deve preferir propriedades como a maneira de acessar seus campos.

Como apenas os campos podem armazenar dados, isso significa que mais classe de campos contém, mais objetos de memória dessa classe serão consumidos. Por outro lado, adicionar novas propriedades a uma classe não aumenta os objetos dessa classe. Aqui está o exemplo.

class OneHundredFields
{
        public int Field1;
        public int Field2;
        ...
        public int Field100;
}

OneHundredFields Instance=new OneHundredFields() // Variable 'Instance' consumes 100*sizeof(int) bytes of memory.

class OneHundredProperties
{
    public int Property1
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    public int Property2
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    ...

    public int Property100
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }
}

OneHundredProperties Instance=new OneHundredProperties() // !!!!! Variable 'Instance' consumes 0 bytes of memory. (In fact a some bytes are consumed becasue every object contais some auxiliarity data, but size doesn't depend on number of properties).

Embora os métodos de propriedade possam fazer qualquer coisa, na maioria dos casos eles servem como uma maneira de acessar os campos dos objetos. Se você deseja tornar um campo acessível a outras classes, pode fazê-lo de duas maneiras.

  1. Tornar os campos públicos - não é aconselhável.
  2. Usando propriedades.

Aqui está uma classe usando campos públicos.

class Name
{
    public string FullName;
    public int YearOfBirth;
    public int Age;
}

Name name=new Name();

name.FullName="Tim Anderson";
name.YearOfBirth=1979;
name.Age=40;

Embora o código seja perfeitamente válido, do ponto de vista do design, ele tem várias desvantagens. Como os campos podem ser lidos e gravados, você não pode impedir que o usuário grave nos campos. Você pode aplicar a readonlypalavra-chave, mas dessa forma, você deve inicializar os campos somente leitura no construtor. Além do mais, nada impede que você armazene valores inválidos em seus campos.

name.FullName=null;
name.YearOfBirth=2200;
name.Age=-140;

O código é válido, todas as atribuições serão executadas, embora ilógicas. Agetem um valor negativo, YearOfBirthestá distante no futuro e não corresponde à idade e FullNameé nulo. Com os campos, você não pode impedir que os usuários class Namecometam esses erros.

Aqui está um código com propriedades que corrige esses problemas.

class Name
{
    private string MFullName="";
    private int MYearOfBirth;

    public string FullName
    {
        get
        {
            return(MFullName);
        }
        set
        {
            if (value==null)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MFullName=value;
        }
    }

    public int YearOfBirth
    {
        get
        {
            return(MYearOfBirth);
        }
        set
        {
            if (MYearOfBirth<1900 || MYearOfBirth>DateTime.Now.Year)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MYearOfBirth=value;
        }
    }

    public int Age
    {
        get
        {
            return(DateTime.Now.Year-MYearOfBirth);
        }
    }

    public string FullNameInUppercase
    {
        get
        {
            return(MFullName.ToUpper());
        }
    }
}

A versão atualizada da classe possui as seguintes vantagens.

  1. FullNamee YearOfBirthsão verificados quanto a valores inválidos.
  2. Agenão é gravável. É calculado deYearOfBirth ano atual.
  3. Uma nova propriedade é FullNameInUppercaseconvertida FullNameem MAIÚSCULAS. Este é um exemplo um pouco artificial de uso de propriedade, em que propriedades são comumente usadas para apresentar valores de campo no formato mais apropriado para o usuário - por exemplo, usando a localidade atual em um numérico específico de DateTimeformato.

Além disso, as propriedades podem ser definidas como virtuais ou substituídas - simplesmente porque são métodos .NET regulares. As mesmas regras se aplicam aos métodos de propriedade e aos métodos regulares.

O C # também suporta indexadores, que são as propriedades que possuem um parâmetro index nos métodos de propriedade. Aqui está o exemplo.

class MyList
{
    private string[]                 MBuffer;

    public MyList()
    {
        MBuffer=new string[100];
    }

    public string this[int Index]
    {
        get
        {
            return(MBuffer[Index]);
        }
        set
        {
            MBuffer[Index]=value;
        }
    }
}

MyList   List=new MyList();

List[10]="ABC";
Console.WriteLine(List[10]);

Como o C # 3.0 permite definir propriedades automáticas. Aqui está o exemplo.

class AutoProps
{
    public int Value1
    {
        get;
        set;
    }

    public int Value2
    {
        get;
        set;
    }
}

Embora class AutoPropscontenha apenas propriedades (ou parece), ele pode armazenar 2 valores e o tamanho dos objetos dessa classe é igual a sizeof(Value1)+sizeof(Value2)= 4 + 4 = 8 bytes.

A razão para isso é simples. Quando você define uma propriedade automática, o compilador C # gera código automático que contém o campo oculto e uma propriedade com métodos de propriedade acessando esse campo oculto. Aqui está o compilador de código produzido.

Aqui está um código gerado pelo ILSpy a partir do assembly compilado. A classe contém campos e propriedades ocultos gerados.

internal class AutoProps
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value1>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value2>k__BackingField;

    public int Value1
    {
        [CompilerGenerated]
        get
        {
            return <Value1>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value1>k__BackingField = value;
        }
    }

    public int Value2
    {
        [CompilerGenerated]
        get
        {
            return <Value2>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value2>k__BackingField = value;
        }
    }
}

Portanto, como você pode ver, o compilador ainda usa os campos para armazenar os valores - já que os campos são a única maneira de armazenar valores em objetos.

Portanto, como você pode ver, embora propriedades e campos tenham sintaxe de uso semelhante, eles são conceitos muito diferentes.Mesmo se você usar propriedades ou eventos automáticos - os campos ocultos são gerados pelo compilador onde os dados reais são armazenados.

Se você precisar tornar um valor de campo acessível ao mundo exterior (usuários de sua classe), não use campos públicos ou protegidos. Os campos sempre devem ser marcados como particulares. As propriedades permitem fazer verificações de valor, formatação, conversões etc. e geralmente tornam seu código mais seguro, mais legível e mais extensível para modificações futuras.

Timmy_A
fonte
4

Além disso, as propriedades permitem que você use a lógica ao definir valores.

Portanto, você pode dizer que deseja definir apenas um valor para um campo inteiro, se o valor for maior que x, caso contrário, lance uma exceção.

Recurso realmente útil.

GurdeepS
fonte
4

Se você usar primitivas de encadeamento, será forçado a usar campos. Propriedades podem quebrar seu código de thread. Além disso, o que Cory disse está correto.

Jonathan C Dickinson
fonte
1
Desde quando? bloquear o seu campo de apoio dentro da propriedade e é a equivilant
Sekhat
1
Propriedades são métodos e não são incorporadas por nenhum JIT CIL hoje. Se você usar primitivas de encadeamento como Intertravado, precisará ter campos. Verifique suas fontes. É certo que 'travar' era a palavra errada a ser usada.
Jonathan C Dickinson
4

(Realmente deve ser um comentário, mas não posso postar um comentário, por favor, desculpe se não for apropriado como um post).

Certa vez, trabalhei em um local onde a prática recomendada era usar campos públicos em vez de propriedades, quando o equivalente equivalente da propriedade teria acessado um campo, como em:

get { return _afield; }
set { _afield = value; }

Seu raciocínio era que o campo público poderia ser convertido em uma propriedade mais tarde no futuro, se necessário. Pareceu-me um pouco estranho na época. A julgar por esses posts, parece que muitos aqui também não concordariam. O que você poderia ter dito para tentar mudar as coisas?

Edit: Devo acrescentar que toda a base de código deste local foi compilada ao mesmo tempo, para que eles pensassem que alterar a interface pública das classes (alterando um campo público para uma propriedade) não era um problema.

Moe Sisko
fonte
Desde o C # 3.0 , o padrão descrito aqui é convenientemente suportado por um recurso chamado Propriedades Auto-Implementadas .
precisa saber é o seguinte
Eu acho que uma das vantagens em C # com Propriedades, pois elas têm a mesma API dos campos, para que os clientes da classe não se importem se estão acessando uma propriedade ou um campo. (Isso NÃO é verdade em C ++, por exemplo). Na criação de protótipos, acho razoável iniciar com campos públicos e migrar para propriedades conforme necessário. Há um desempenho e memória atingidos com propriedades e há digitação extra. Eles não são livres. Mas, se você mudar de idéia, não precisará refatorar nenhum código dependente.
Marque Lakata
As propriedades não podem ser usadas como parâmetros OUT ou REF, portanto, alterar um campo em uma propriedade pode levar a erros de compilação na linha. Se o valor fosse implementado como uma propriedade desde o início, nunca teria sido usado como parâmetros OUT ou REF (VAR em Pascal / Delphi), e qualquer alteração feita no getter / setter seria transparente para o uso.
HeartWare
4

Tecnicamente, não acho que exista uma diferença, porque as propriedades são apenas wrappers em torno dos campos criados pelo usuário ou criados automaticamente pelo compilador. O objetivo das propriedades é impor o encapsulamento e oferecer um recurso leve e semelhante ao método. É apenas uma prática ruim declarar campos como públicos, mas não há nenhum problema.

Brahim Boulkriat
fonte
4

Campos são variáveis ​​de membros comuns ou instâncias de membros de uma classe. Propriedades são uma abstração para obter e definir seus valores . As propriedades também são chamadas de acessadores porque oferecem uma maneira de alterar e recuperar um campo se você expuser um campo na classe como privado. Geralmente, você deve declarar suas variáveis ​​de membro privadas e, em seguida, declarar ou definir propriedades para elas.

  class SomeClass
  {
     int numbera; //Field

     //Property 
    public static int numbera { get; set;}

  }
Vasim Shaikh
fonte
3

As propriedades encapsulam campos, permitindo que você execute um processamento adicional no valor a ser definido ou recuperado. Geralmente, é um exagero usar propriedades se você não estiver executando nenhum pré ou pós-processamento no valor do campo.

Erik Burger
fonte
1
não, eu sempre uso propriedades, ele permite a flexibilidade de alterar a implementação a qualquer momento sem interromper sua API.
Sekhat
Em relação à evolução da API, você pode usar campos para dados particulares sem problemas. Também em casos ímpares em que você deseja compartilhar dados em uma montagem, você pode fornecer acesso 'interno' aos campos.
21118 Daniel Earwicker
3

Na IMO, as propriedades são apenas os pares de funções / métodos / interfaces "SetXXX ()" "GetXXX ()" que usamos anteriormente, mas são mais concisos e elegantes.

Junchao Xu
fonte
3

Tradicionalmente, os campos privados são definidos pelos métodos getter e setter. Por uma questão de menos código, você pode usar propriedades para definir campos.

Chris Paine
fonte
3

quando você tem uma classe que é "Carro". As propriedades são cor, forma ..

Onde os campos são variáveis ​​definidas no escopo de uma classe.

user406580
fonte
3

Da Wikipedia - Programação orientada a objetos :

A programação orientada a objetos (OOP) é ​​um paradigma de programação baseado no conceito de "objetos", que são estruturas de dados que contêm dados, na forma de campos , geralmente conhecidos como atributos; e código, na forma de procedimentos, geralmente conhecidos como métodos . (enfase adicionada)

Na verdade, as propriedades fazem parte do comportamento de um objeto, mas são projetadas para dar aos consumidores do objeto a ilusão / abstração de trabalhar com os dados do objeto.

Zev Spitz
fonte
3

Meu design de um campo é que um campo precisa ser modificado apenas por seu pai, daí a classe. Resultado, a variável se torna privada, para que eu possa dar o direito de ler as classes / métodos fora, passo pelo sistema de propriedades apenas com o Get. O campo é recuperado pela propriedade e somente leitura! Se você quiser modificá-lo, precisará passar por métodos (por exemplo, o construtor) e acho que, graças a essa maneira de protegê-lo, temos um melhor controle sobre nosso código, porque "flangeamos". Pode-se muito bem sempre colocar tudo em público, então todos os casos possíveis, a noção de variáveis ​​/ métodos / classes etc ... na minha opinião é apenas uma ajuda para o desenvolvimento, manutenção do código. Por exemplo, se uma pessoa retoma um código com campos públicos, ela pode fazer qualquer coisa e, portanto, coisas "ilógicas" em relação ao objetivo, a lógica do motivo pelo qual o código foi escrito. É o meu ponto de vista.

Quando eu uso um campo privado de modelo clássico / propriedades públicas somente leitura, para 10 campos privados, eu devo escrever 10 propriedades públicas! O código pode ser muito grande mais rápido. Descobri o setter privado e agora só uso propriedades públicas com um setter privado. O levantador cria em segundo plano um campo privado.

Por isso, meu antigo estilo de programação clássico era:

public class MyClass
{
 private int _id;
 public int ID { get { return _id; } }
 public MyClass(int id)
 {
  _id = id;
 }
}

Meu novo estilo de programação:

public class MyClass
{
 public int ID { get; private set; }
 public MyClass(int id)
 {
  ID = id;
 }
}
Tony Pinot
fonte
Sim, meu mal, desculpe!
Tony Pinot
3

Pense bem: você tem um quarto e uma porta para entrar neste quarto. Se você quiser verificar como quem está entrando e proteger seu quarto, use as propriedades, caso contrário elas não terão nenhuma porta e todas entrarão facilmente sem regulamentação

class Room {
   public string sectionOne;
   public string sectionTwo;
}

Room r = new Room();
r.sectionOne = "enter";

As pessoas estão entrando na seçãoOne muito facilmente, não houve nenhuma verificação

class Room 
{
   private string sectionOne;
   private string sectionTwo;

   public string SectionOne 
   {
      get 
      {
        return sectionOne; 
      }
      set 
      { 
        sectionOne = Check(value); 
      }
   }
}

Room r = new Room();
r.SectionOne = "enter";

Agora você conferiu a pessoa e sabe se ela tem algo de ruim com ela

user8080469
fonte
3

Campos são as variáveis ​​nas classes. Campos são os dados que você pode encapsular através do uso de modificadores de acesso.

As propriedades são semelhantes a Fields, pois definem estados e dados associados a um objeto.

Ao contrário de um campo, uma propriedade possui uma sintaxe especial que controla como uma pessoa lê e grava os dados, conhecidos como operadores get e set. A lógica do conjunto geralmente pode ser usada para fazer a validação.

Neil Meyer
fonte
2

As propriedades são um tipo especial de membro da classe. Nas propriedades, usamos um método Set ou Get predefinido. Eles usam acessadores através dos quais podemos ler, escrever ou alterar os valores dos campos particulares.

Por exemplo, vamos usar uma classe chamada Employee, com campos particulares para nome, idade e Employee_Id. Não podemos acessar esses campos de fora da classe, mas podemos acessar esses campos particulares por meio de propriedades.

Por que usamos propriedades?

Tornar público o campo da classe e expô-lo é arriscado, pois você não terá controle sobre o que é atribuído e devolvido.

Para entender isso claramente com um exemplo, vamos dar uma aula de aluno que tenha ID, marca de passagem, nome. Agora, neste exemplo, algum problema com o campo público

  • O ID não deve ser -ve.
  • O nome não pode ser definido como nulo
  • A marca de aprovação deve ser somente leitura.
  • Se o nome do aluno estiver ausente, nenhum nome deve ser retornado.

Para remover esse problema, usamos o método Get e set.

// A simple example
public class student
{
    public int ID;
    public int passmark;
    public string name;
}

public class Program
{
    public static void Main(string[] args)
    {
       student s1 = new student();
       s1.ID = -101; // here ID can't be -ve
       s1.Name = null ; // here Name can't be null
    }
}

Agora vamos dar um exemplo do método get e set

public class student
{
    private int _ID;
    private int _passmark;
    private string_name ;
    // for id property
    public void SetID(int ID)
    {
        if(ID<=0)
        {
            throw new exception("student ID should be greater then 0");
        }
        this._ID = ID;
    }
    public int getID()
    {
        return_ID;
    }
}
public class programme
{
    public static void main()
    {
        student s1 = new student ();
        s1.SetID(101);
    }
    // Like this we also can use for Name property
    public void SetName(string Name)
    {
        if(string.IsNullOrEmpty(Name))
        {
            throw new exeception("name can not be null");
        }
        this._Name = Name;
    }
    public string GetName()
    {
        if( string.IsNullOrEmpty(This.Name))
        {
            return "No Name";
        }
        else
        {
            return this._name;
        }
    }
        // Like this we also can use for Passmark property
    public int Getpassmark()
    {
        return this._passmark;
    }
}
ahmed alkhatib
fonte
2

Informações adicionais: por padrão, os acessadores de obtenção e configuração são tão acessíveis quanto a própria propriedade. Você pode controlar / restringir a acessibilidade do acessador individualmente (para obter e definir) aplicando modificadores de acesso mais restritivos.

Exemplo:

public string Name
{
    get
    {
        return name;
    }
    protected set
    {
        name = value;
    }
}

Aqui, get ainda é acessado publicamente (como a propriedade é pública), mas set está protegido (um especificador de acesso mais restrito).

code_doctor
fonte
2

Propriedades são usadas para expor o campo. Eles usam acessadores (set, get) através dos quais os valores dos campos privados podem ser lidos, gravados ou manipulados.

Propriedades não nomeiam os locais de armazenamento. Em vez disso, eles têm acessadores que lêem, gravam ou calculam seus valores.

Usando propriedades, podemos definir a validação do tipo de dados que é definido em um campo.

Por exemplo, temos a idade do campo inteiro privado em que devemos permitir valores positivos, pois a idade não pode ser negativa.

Podemos fazer isso de duas maneiras, usando getter e setters e usando a propriedade

 Using Getter and Setter

    // field
    private int _age;

    // setter
    public void set(int age){
      if (age <=0)
       throw new Exception();

      this._age = age;
    }

    // getter
    public int get (){
      return this._age;
    }

 Now using property we can do the same thing. In the value is a key word

    private int _age;

    public int Age{
    get{
        return this._age;
    }

    set{
       if (value <= 0)
         throw new Exception()
       }
    }

Propriedade implementada automaticamente se não fizermos lógica em obter e configurar acessadores, podemos usar a propriedade implementada automaticamente.

Quando você usa compilações de propriedades implementadas automaticamente, cria um campo privado e anônimo que só pode ser acessado por meio de acessadores get e set.

public int Age{get;set;}

Propriedades abstratas Uma classe abstrata pode ter uma propriedade abstrata, que deve ser implementada na classe derivada

public abstract class Person
   {
      public abstract string Name
      {
         get;
         set;
      }
      public abstract int Age
      {
         get;
         set;
      }
   }

// overriden something like this
// Declare a Name property of type string:
  public override string Name
  {
     get
     {
        return name;
     }
     set
     {
        name = value;
     }
  }

Podemos definir uma propriedade em particular. Nisto podemos definir em particular a propriedade auto (definida com na classe)

public int MyProperty
{
    get; private set;
}

Você pode conseguir o mesmo com este código. Nesse conjunto de propriedades, o recurso não está disponível, pois precisamos definir o valor para o campo diretamente.

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}
Nayas Subramanian
fonte
2

A grande maioria dos casos será um nome de propriedade que você acessa em vez de um nome de variável ( campo ). O motivo disso é que é considerada uma boa prática no .NET e no C # em particular para proteger todos os dados de uma classe. , seja uma variável de instância ou estática (variável de classe), porque está associada a uma classe.

Proteja todas essas variáveis ​​com propriedades correspondentes que permitem definir, definir e obter acessadores e fazer coisas como validação ao manipular essas partes de dados.

Mas em outros casos, como a classe Math (espaço de nome System), existem algumas propriedades estáticas que são incorporadas à classe. um dos quais é a constante matemática PI

por exemplo. Math.PI

e como o PI é um dado bem definido, não precisamos ter várias cópias do PI, sempre terá o mesmo valor. Portanto, variáveis ​​estáticas às vezes são usadas para compartilhar dados entre objetos de uma classe, mas elas também são comumente usadas para informações constantes, nas quais você só precisa de uma cópia de uma parte dos dados.

Nermien Barakat
fonte