This article has been localized into Portuguese by the community.
Propriedades
No artigo anterior, discutimos os campos. Eles são como variáveis globais para uma classe, permitindo o acesso a partir de todos os métodos. Também discutimos brevemente o facto de que os campos PODEM ser acessados a partir de outras classes se forem marcados como públicos, mas que isto geralmente não é recomendado. Para variáveis/campos que pretende acessar de fora da sua classe, deve em vez disso utilizar propriedades.
Quando declares um campo como público, estás a dar acesso completo a ele a partir de fora – outras classes podem fazer o que quiserem com ele, sem qualquer aviso à classe que o declarou. As propriedades devolvem o controlo à classe que o declarou, ao especificar se um campo é apenas de leitura ou de escrita, e até permitindo que a classe que o declarou verifique e manipule o valor antes de o devolver ou atribuir ao campo.
Uma propriedade parece um pouco como uma fusão entre um campo e um método, porque é declarada de forma semelhante a um campo, com visibilidade, um tipo de dado e um nome, mas também tem um corpo, como um método, para controlar o comportamento:
public string Name
{
get { return _name; }
set { _name = value; }
}Repara nas palavras-chave especiais get e set. Elas são usadas exclusivamente para propriedades, para controlar o comportamento ao ler (get) e escrever (set) o campo. Podes ter propriedades com apenas uma implementação de get OU set, para criar propriedades apenas de leitura ou apenas de escrita, e até podes controlar a visibilidade das implementações de get ou set, por exemplo, para criar uma propriedade que possa ser lida de qualquer lugar (pública), mas apenas modificada de dentro da classe que a declarou (privada).
Também vais reparar que me refiro a um campo chamado _name. Terás de declarar esse campo na tua classe também, para que a tua propriedade o possa utilizar. Um padrão de uso comum para campos e propriedades será algo assim:
private string _name = "John Doe";
public string Name
{
get { return _name; }
set { _name = value; }
}Agora podes ver como o campo e a propriedade trabalham em conjunto: O método get irá devolver o valor do campo _name, enquanto o método set irá atribuir o valor passado ao campo _name. No método set, usamos a palavra-chave especial *value*, que, nesta situação específica, se refere ao valor passado para a propriedade.
Portanto, isto é basicamente o mais simples que se pode fazer e, neste momento, não estamos a fazer nada que não pudesse ser realizado com um simples campo público. Mas, mais tarde, podes decidir que queres ter mais controlo sobre como outras classes podem trabalhar com o nome e, uma vez que implementaste isto como uma propriedade, estás livre para modificar a implementação sem afetar quem estiver a usar a tua classe. Por exemplo, a propriedade Name poderia ser modificada para parecer assim:
private string _name = "John Doe";
public string Name
{
get
{
return _name.ToUpper();
}
set
{
if(!value.Contains(" "))
throw new Exception("Please specify both first and last name!");
_name = value;
}
}O método get agora garante que o valor devolvido está sempre em MAIÚSCULAS, independentemente de qual seja o caso do campo de apoio (_name). No método set, adicionámos algumas linhas de código para verificar se o valor passado contém um espaço, porque decidimos que o nome deve sempre consistir de um primeiro nome e um apelido – se não for o caso, é lançada uma exceção. Isto é tudo muito simples e rudimentar, mas deve ilustrar o nível completo de controlo que se obtém ao usar propriedades.
Propriedades apenas de leitura
A maioria das propriedades que verás nos exemplos deste tutorial serão tanto de leitura como de escrita, porque essa é a utilização mais comum das propriedades, mas não tem de ser sempre assim. Em primeiro lugar, podes declarar uma propriedade com apenas um método get, assim:
private string _name = "John Doe";
public string Name
{
get { return _name; }
}Neste caso, já não podes alterar a propriedade "Name" – apenas podes lê-la, e o compilador gerará um erro se tentares atribuir um valor a ela. No entanto, ainda podes alterar o valor dela de dentro da classe, já que podes simplesmente atribuir um novo valor ao campo de apoio "_name". Fazer isto, no entanto, anula uma das maiores vantagens das propriedades: A capacidade de controlar sempre se um valor pode ser aceite. Como já falámos, o método set é uma ótima forma de realizar a validação do valor, mas se atribuíres um novo valor ao campo _name de múltiplos lugares, porque a propriedade é apenas de leitura, não obterás essa validação.
Felizmente para nós, o C# oferece uma solução para isto: Podes definir um método set na propriedade, mas limitar a sua visibilidade, usando, por exemplo, a palavra-chave private ou protected. Isto vai dar-te o melhor dos dois mundos, onde ainda podes atribuir um valor à propriedade de dentro da classe (ou de qualquer classe herdada, se usares a palavra-chave protected) e validá-lo de acordo. Aqui está um exemplo:
private string _name = "John Doe";
public string Name
{
get { return _name; }
private set
{
if(IsValidName(value))
this._name = value;
}
}
public bool IsValidName(string name)
{
return name.EndsWith("Doe");
}A principal diferença aqui é simplesmente a palavra-chave "private" logo à frente da palavra-chave "set", e como mencionado, podes substituí-la por, por exemplo, "protected" ou "internal", dependendo das tuas necessidades.
Propriedades auto-implementadas
Em alguns casos, não precisas de todo o controlo sobre um campo e pode parecer incomodativo implementar tanto um campo quanto uma propriedade com os métodos get e set a fazerem nada além do que vimos no primeiro exemplo. Podes ser tentado a simplesmente declarar a tua variável como um campo público para evitar todo este esforço extra. Mas não faças isso! Felizmente para todos nós, a Microsoft decidiu adicionar propriedades auto-implementadas na versão 3 do C#, o que te vai poupar várias linhas de código. Basta considerar a diferença:
Propriedade regular com um campo de apoio declarado:
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}O mesmo comportamento, mas com uma propriedade auto-implementada:
public string Name { get; set; }Repara que os métodos get e set estão vazios e que nenhum campo privado de apoio é declarado – em outras palavras, agora podemos alcançar o mesmo comportamento que no primeiro exemplo, mas com uma única linha de código! Tenha em mente que o campo privado de apoio ainda existirá em tempo de execução – ele será auto-implementado pelo compilador, como o nome sugere. Se mais tarde decidires que precisas de mais controlo sobre esta propriedade específica, podes simplesmente mudá-la para uma combinação regular de campo/propriedade com a implementação desejada dos métodos get e set.
Repara que ainda tens um mecanismo importante de controlo das propriedades regulares ao usar propriedades auto-implementadas: Podes omitir a palavra-chave `set` para criar uma propriedade apenas de leitura, por exemplo, assim:
public string ReadOnlyProperty { get; }Propriedades apenas de escrita (write-only) não são permitidas quando se utilizam propriedades auto-implementadas.
Propriedades auto-implementadas com valores padrão
Antes da versão 6 do C#, não era possível definir um valor default para uma propriedade auto-implementada – para isso, seria necessário declarar um campo de apoio, o que te permitiria inicializar a variável com um valor, assim:
private string _name = "John Doe";
public string Name
{
get { return _name; }
set { _name = value; }
}Mas, na versão 6 do C#, a Microsoft finalmente adicionou a capacidade de inicializar uma propriedade auto-implementada com um valor default, assim:
public string Name { get; set; } = "John Doe";Propriedades com corpo de expressão
Outra funcionalidade relacionada com propriedades que a Microsoft implementou no C# 6.0 e 7.0 são os membros com corpo de expressão. Isto permite-te escrever expressões de uma linha para as tuas propriedades e métodos – neste caso, vamos ver como usá-las para os teus métodos get/set de forma a ocupar menos espaço e exigir menos digitação:
private string name;
public string Name
{
get => name;
set => name = value;
}
Se a tua propriedade for apenas de leitura, a sintaxe pode ser ainda mais curta:
public string Name => "John Doe";Claro, isto também funciona se precisares de fazer algo antes de devolver o valor, assim:
public string Name { get; set; } = "John Doe";
public string FirstName => this.Name.Substring(0, this.Name.IndexOf(" "));Como podes ver, isto permite-te definir um método get mas sem as palavras-chave get e return, enquanto te incentiva a manter tudo numa única linha, em vez de várias linhas.
Resumo
As propriedades dão às tuas classes mais controlo sobre como os campos podem ser acedidos e manipulados, e devem sempre ser utilizadas quando quiseres dar acesso a campos a partir de fora da classe que os declarou.