Propriedades (Guia de Programação em C#)
Uma propriedade é um membro que fornece um mecanismo flexível para ler, gravar ou calcular o valor de um campo de dados. As propriedades aparecem como membros de dados públicos, mas são implementadas como métodos especiais chamados acessadores. Esse recurso permite que os chamadores acessem os dados facilmente e ainda ajuda a promover a segurança e a flexibilidade dos dados. A sintaxe das propriedades é uma extensão natural dos campos. Um campo define um local de armazenamento:
public class Person
{
public string? FirstName;
// Omitted for brevity.
}
Propriedades implementadas automaticamente
Uma definição de propriedade contém declarações para um get
e set
acessador que recupera e atribui o valor dessa propriedade:
public class Person
{
public string? FirstName { get; set; }
// Omitted for brevity.
}
O exemplo anterior mostra uma propriedade implementada automaticamente. O compilador gera um campo de suporte oculto para a propriedade. O compilador também implementa o corpo dos get
e set
acessadores. Todos os atributos são aplicados à propriedade implementada automaticamente. Você pode aplicar o atributo ao campo de suporte gerado pelo compilador especificando a field:
tag no atributo.
Você pode inicializar uma propriedade com um valor diferente do padrão definindo um valor após a chave de fechamento da propriedade. Você pode preferir que o valor inicial da FirstName
propriedade seja a cadeia de caracteres vazia em vez de null
. Você deve especificar isso como mostrado no código a seguir:
public class Person
{
public string FirstName { get; set; } = string.Empty;
// Omitted for brevity.
}
Controlo de acesso
Os exemplos anteriores mostraram propriedades de leitura/gravação. Você também pode criar propriedades somente leitura ou dar acessibilidade diferente ao conjunto e obter acessadores. Suponha que sua Person
classe só deve habilitar a FirstName
alteração do valor da propriedade de outros métodos nessa classe. Você pode dar ao acessor private
definido acessibilidade em vez de public
:
public class Person
{
public string? FirstName { get; private set; }
// Omitted for brevity.
}
A FirstName
propriedade pode ser lida a partir de qualquer código, mas pode ser atribuída apenas a Person
partir do código na classe.
Você pode adicionar qualquer modificador de acesso restritivo ao conjunto ou obter acessadores. Um modificador de acesso em um acessador individual deve ser mais restritivo do que o acesso da propriedade. O código anterior é legal porque a FirstName
propriedade é public
, mas o acessador definido é private
. Não foi possível declarar um private
imóvel com acessório public
. As declarações de propriedade também podem ser declaradas protected
, internal
, protected internal
, ou, mesmo private
.
Existem dois modificadores de acesso especiais para set
acessadores:
- Um
set
acessador pode terinit
como modificador de acesso. Esseset
acessador pode ser chamado somente a partir de um inicializador de objeto ou dos construtores do tipo. É mais restritivo do queprivate
noset
acessório. - Uma propriedade implementada automaticamente pode declarar um
get
acessador sem umset
acessador. Nesse caso, o compilador permite que oset
acessador seja chamado apenas a partir dos construtores do tipo. É mais restritivo do que oinit
acessador noset
acessador.
Modifique a Person
classe da seguinte maneira:
public class Person
{
public Person(string firstName) => FirstName = firstName;
public string FirstName { get; }
// Omitted for brevity.
}
O exemplo anterior requer que os chamadores usem o construtor que inclui o FirstName
parâmetro. Os chamadores não podem usar inicializadores de objeto para atribuir um valor à propriedade. Para suportar inicializadores, você pode tornar o set
acessador um init
acessador, conforme mostrado no código a seguir:
public class Person
{
public Person() { }
public Person(string firstName) => FirstName = firstName;
public string? FirstName { get; init; }
// Omitted for brevity.
}
Esses modificadores são frequentemente usados com o modificador para forçar a required
inicialização adequada.
Propriedades obrigatórias
O exemplo anterior permite que um chamador crie um Person
usando o construtor padrão, sem definir a FirstName
propriedade. A propriedade mudou o tipo para uma cadeia de caracteres anulável . A partir do C# 11, você pode exigir que os chamadores definam uma propriedade:
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName) => FirstName = firstName;
public required string FirstName { get; init; }
// Omitted for brevity.
}
O código anterior faz duas alterações na Person
classe. Primeiro, a declaração de FirstName
propriedade inclui o required
modificador. Isso significa que qualquer código que crie um novo Person
deve definir essa propriedade usando um inicializador de objeto. Em segundo lugar, o construtor que usa um firstName
parâmetro tem o System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute atributo. Este atributo informa o compilador que este construtor define todos os required
membros. Os chamadores que usam esse construtor não são obrigados a definir required
propriedades com um inicializador de objeto.
Importante
Não confunda required
com não-anulável. É válido definir uma required
propriedade como null
ou default
. Se o tipo não for anulável, como string
nesses exemplos, o compilador emitirá um aviso.
var aPerson = new Person("John");
aPerson = new Person{ FirstName = "John"};
// Error CS9035: Required member `Person.FirstName` must be set:
//aPerson2 = new Person();
Definições do corpo da expressão
Os acessadores de propriedade geralmente consistem em instruções de linha única. Os acessadores atribuem ou retornam o resultado de uma expressão. Você pode implementar essas propriedades como membros com corpo de expressão. As definições do corpo da expressão consistem no =>
token seguido pela expressão a ser atribuída ou recuperada da propriedade.
As propriedades somente leitura podem implementar o get
acessador como um membro com corpo de expressão. O exemplo a seguir implementa a propriedade somente Name
leitura como um membro com corpo de expressão:
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public required string FirstName { get; init; }
public required string LastName { get; init; }
public string Name => $"{FirstName} {LastName}";
// Omitted for brevity.
}
A Name
propriedade é uma propriedade calculada. Não há campo de apoio para Name
. A propriedade calcula-o de cada vez.
Propriedades com campos de apoio
Você pode misturar o conceito de uma propriedade computada com um campo privado e criar uma propriedade avaliada em cache. Por exemplo, atualize a FullName
propriedade para que a formatação da cadeia de caracteres aconteça no primeiro acesso:
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public required string FirstName { get; init; }
public required string LastName { get; init; }
private string? _fullName;
public string FullName
{
get
{
if (_fullName is null)
_fullName = $"{FirstName} {LastName}";
return _fullName;
}
}
}
Essa implementação funciona porque as propriedades e LastName
são FirstName
somente leitura. As pessoas podem mudar de nome. A atualização das FirstName
propriedades e LastName
para permitir set
acessadores exige que você invalide qualquer valor armazenado em cache para fullName
. Você modifica os set
acessadores da FirstName
propriedade e LastName
para que o fullName
campo seja calculado novamente:
public class Person
{
private string? _firstName;
public string? FirstName
{
get => _firstName;
set
{
_firstName = value;
_fullName = null;
}
}
private string? _lastName;
public string? LastName
{
get => _lastName;
set
{
_lastName = value;
_fullName = null;
}
}
private string? _fullName;
public string FullName
{
get
{
if (_fullName is null)
_fullName = $"{FirstName} {LastName}";
return _fullName;
}
}
}
Esta versão final avalia a FullName
propriedade apenas quando necessário. A versão calculada anteriormente é usada, se válida. Caso contrário, o cálculo atualiza o valor armazenado em cache. Os desenvolvedores que usam essa classe não precisam saber os detalhes da implementação. Nenhuma dessas alterações internas afeta o uso do objeto Person.
A partir do C# 13, você pode criar partial
propriedades em partial
classes. A declaração de implementação de uma partial
propriedade não pode ser uma propriedade implementada automaticamente. Uma propriedade implementada automaticamente usa a mesma sintaxe de uma declaração de propriedade parcial declarada.
Propriedades
As propriedades são uma forma de campos inteligentes em uma classe ou objeto. De fora do objeto, eles aparecem como campos no objeto. No entanto, as propriedades podem ser implementadas usando a paleta completa da funcionalidade C#. Você pode fornecer validação, acessibilidade diferente, avaliação preguiçosa ou quaisquer requisitos que seus cenários precisem.
- Propriedades simples que não exigem código de acesso personalizado podem ser implementadas como definições de corpo de expressão ou como propriedades implementadas automaticamente.
- 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 de propriedade definido é usado para atribuir um novo valor. Um acessador de propriedade init é usado para atribuir um novo valor somente durante a construção do objeto. Esses acessadores podem ter diferentes níveis de acesso. Para obter mais informações, consulte Restringindo a acessibilidade do Accessor.
- A palavra-chave value é usada para definir o valor que o
set
acessador ouinit
acessador está atribuindo. - As propriedades podem ser leitura-gravação (elas têm um
get
acessador e umset
acessador), somente leitura (elas têm umget
acessador, mas nãoset
acessam) ou somente gravação (elas têm umset
acessador, mas nãoget
acessam). Propriedades somente gravação são raras.
Especificação da linguagem C#
Para obter mais informações, consulte Propriedades na especificação da linguagem C#. A especificação da linguagem é a fonte definitiva para a sintaxe e o uso do C#.