A programação orientada a objetos (POO) é um paradigma que organiza o código de forma modular e reutilizável. Um dos pilares desse paradigma é o encapsulamento, que visa proteger os dados e o comportamento de uma classe, tornando-os acessíveis e modificáveis de maneira controlada. Um dos principais mecanismos para alcançar o encapsulamento em C# é o uso de propriedades com os modificadores “get” e “set”. Neste artigo, exploraremos como essas propriedades podem ser utilizadas para proteger os dados, promovendo uma arquitetura mais segura, modular e de fácil manutenção.
O encapsulamento é o princípio que busca esconder os detalhes internos de implementação de uma classe, permitindo que sua interface pública (as propriedades e métodos) seja usada sem que o consumidor da classe precise entender ou acessar diretamente seus dados internos. Esse conceito não só protege o estado interno da classe, mas também oferece a oportunidade de validar e controlar como os dados são acessados e modificados.
Para entendermos melhor, vamos imaginar que estamos construindo uma classe “ContaBancaria”. Sem encapsulamento, qualquer código poderia acessar diretamente o saldo da conta e alterá-lo sem restrições:
public class ContaBancaria
{
public decimal Saldo;
}
var conta = new ContaBancaria();
conta.Saldo = -500; // O saldo foi alterado para um valor inválido
Com encapsulamento, podemos proteger esse campo, tornando o acesso ao saldo restrito e controlado:
public class ContaBancaria
{
private decimal saldo; // Mudamos o campo para privado
public decimal Saldo
{
get { return saldo; }
set
{
if (value < 0)
throw new ArgumentException("O saldo não pode ser negativo.");
saldo = value;
}
}
}
Nesse exemplo, usamos uma propriedade com um “set” que inclui uma lógica de validação para garantir que o saldo (value) não seja negativo, protegendo o estado da classe.
Em C#, uma propriedade é um mecanismo que permite encapsular o acesso a um campo de uma classe. O uso das palavras-chave “get” e “set” permite criar uma interface controlada para acessar e modificar o valor de um campo.
Quando não é necessária lógica adicional para o “get” ou “set”, você pode usar propriedades automáticas, onde o compilador cuida internamente da implementação dos campos:
public class Pessoa
{
public string Nome { get; set; }
}
Esse código permite o acesso à propriedade “Nome” com os métodos “get” e “set”. No entanto, esse método não permite nenhuma validação ou controle.
Você pode adicionar lógica personalizada dentro dos métodos “get” e “set”. Vamos usar um exemplo de uma classe “Pessoa” que valida a idade antes de permitir que ela seja modificada:
public class Pessoa
{
private int idade;
public int Idade
{
get { return idade; }
set
{
if (value < 0)
throw new ArgumentException("Idade não pode ser negativa.");
idade = value;
}
}
}
Neste exemplo, a propriedade “Idade” controla a alteração do campo “idade”, garantindo que a idade seja sempre válida.
Em C#, você pode definir a visibilidade de um “get” ou “set” usando modificadores de acesso. Esses modificadores determinam a acessibilidade da propriedade e seu valor.
Se você deseja que uma propriedade seja somente de leitura para os consumidores da classe, mas ainda permita modificações dentro da própria classe, você pode usar “private set”:
public class Pessoa
{
public string Nome { get; private set; }
public Pessoa(string nome)
{
Nome = nome;
}
}
var pessoa = new Pessoa("João");
Console.WriteLine($"Nome: {pessoa.Nome}");
Neste caso, a propriedade “Nome” só pode ser atribuída por meio do construtor, impedindo a modificação direta do valor (por exemplo, Pessoa.Nome = “Pedro” não seria permitido). O método “get” não é privado, o que significa que a propriedade pode ser acessada e lida de fora da classe.
Quando você deseja que uma propriedade seja somente leitura, ou seja, seu valor pode ser acessado mas nunca modificado após a inicialização, você pode criar uma propriedade com apenas um “get”:
public class Produto
{
public decimal Preco { get; }
public Produto(decimal preco)
{
Preco = preco;
}
}
Neste caso, “Preco” só pode ser atribuído durante a construção do objeto, garantindo que o valor não seja alterado acidentalmente após a criação.
Uma das práticas recomendadas em C# é manter os campos de dados internos de uma classe privados e expô-los de forma controlada através de propriedades públicas. Isso permite que você adicione lógica de validação, formatação e outras operações sem expor diretamente os campos.
public class Pessoa
{
private string nome;
public string Nome
{
get { return nome; }
set { nome = value.Trim(); } // Remover espaços extras ao atribuir
}
}
Neste exemplo, a propriedade “Nome” controla o acesso ao campo privado “nome” e aplica uma lógica para remover espaços extras antes de atribuir um valor ao campo.
Agora que entendemos como funciona o encapsulamento, vamos aplicá-lo em uma situação real. Vamos simular um sistema de venda de lanches onde vamos criar uma classe “Pedido” com uma lista de “Itens”. Cada Item terá um preço, e a classe “Pedido” calculará o “PrecoTotal” dinamicamente com base nos preços dos itens.
Vamos iniciar criando a classe “Item” e “Pedido”:
public class Item
{
public string Nome { get; set; }
public decimal Preco { get; set; }
public Item(string nome, decimal preco)
{
Nome = nome;
Preco = preco;
}
}
public class Pedido
{
public List- Itens { get; set; } = new List
- ();
public decimal PrecoTotal
{
get
{
return Itens.Sum(item => item.Preco);
}
}
public void AdicionarItem(Item item)
{
Itens.Add(item);
}
}
No objeto “Pedido”, teremos uma lista de “Item” contendo os itens da venda. Além disso, teremos uma propriedade chamada “PrecoTotal”, que será uma propriedade calculada, responsável por retornar o preço total do pedido. Esse cálculo é feito utilizando o método “Sum” do LINQ, que soma todos os valores presentes na propriedade “Preco” de cada item. Também vamos adicionar o método “AdicionarITem” para adicionar novos itens à lista de pedidos.
Agora vamos implementar essa lógica:
public class Program
{
public static void Main()
{
var item1 = new Item("X-Tudo", 20.50m);
var item2 = new Item("X-Salada", 10.75m);
var item3 = new Item("X-Egg", 8.99m);
var pedido = new Pedido();
pedido.AdicionarItem(item1);
pedido.AdicionarItem(item2);
pedido.AdicionarItem(item3);
Console.WriteLine($"Preço total do pedido: R$ {pedido.PrecoTotal:F2}");
}
}
No exemplo acima, criamos três itens: X-Tudo, X-Salada e X-Egg. Em seguida, instanciamos um novo “Pedido” e adicionamos esses itens utilizando o método “AdicionarItem”. Por fim, mostramos o preço total do pedido calculado dinamicamente. Isso é muito útil, pois não precisamos realizar manualmente a soma dos valores de todos os itens da lista. Basta acessar a propriedade “PrecoTotal”, e o valor será calculado automaticamente.
Se você é Desenvolvedor .NET Júnior e quer acelerar sua carreira até nível Pleno com salário de R$7k+, ou mesmo busca a primeira vaga, conheça a Mentoria .NET Start: Clique aqui
Se é Desenvolvedor .NET Pleno ou Sênior e quer virar referência técnica em sua equipe e mercado, com salário de R$10k+, conheça a Mentoria .NET Expert: Clique aqui
O uso de propriedades com “get” e “set” em C# é uma das melhores práticas de encapsulamento. Ao proteger os campos internos da classe e fornecer uma interface controlada para acesso e modificação, você melhora a segurança, modularidade e manutenção do seu código. Além disso, o uso de propriedades permite que você adicione lógica de validação e outras verificações sem comprometer a integridade dos dados.