Skip to main content

Construtores | Classes | Conceitos

  • Construtores | Classes | Conceitos

O que DEVEM conter, o que NÃO devem conter e quais tipos existem

info

Exemplos em C#


🎯 Objetivo de um construtor

Um construtor existe para colocar o objeto em um estado válido. Apenas isso.

Ele não existe para:

  • executar lógica de negócio
  • acessar rede
  • abrir conexão
  • fazer I/O
  • “preparar” o mundo externo

✅ O que PODE (e deve) ter em um construtor

1️⃣ Atribuição de dependências

Uso clássico com DI.

public class OrderService
{
private readonly IRepository _repo;

public OrderService(IRepository repo)
{
_repo = repo ?? throw new ArgumentNullException(nameof(repo));
}
}

✔️ Correto ✔️ Previsível ✔️ Testável


2️⃣ Validação de invariantes

Regras estruturais, não de negócio.

public class Email
{
public string Value { get; }

public Email(string value)
{
ArgumentNullException.ThrowIfNullOrWhiteSpace(value);

if (!value.Contains("@"))
throw new ArgumentException("Email inválido");

Value = value;
}
}

✔️ Garante estado válido ✔️ Falha cedo (fail fast)


3️⃣ Inicialização de estado simples

Sem efeitos colaterais.

public class Cache
{
private readonly Dictionary<string, string> _data = new();

public Cache() { }
}

✔️ Seguro ✔️ Determinístico


4️⃣ Inicialização de propriedades obrigatórias

Especialmente em records ou DTOs imutáveis.

public record User(Guid Id, string Name);

❌ O que NÃO deve existir em um construtor (regra de ouro)

🚫 1️⃣ I/O (rede, disco, banco, mensageria)

// ERRADO
public class RabbitManager
{
public RabbitManager()
{
_connection = factory.CreateConnection(); // ❌
}
}

Problemas:

  • Exceção inesperada
  • DI frágil
  • Retry impossível
  • Testes difíceis

🚫 2️⃣ Lógica de negócio

// ERRADO
public OrderService()
{
CriarPedidoInicial();
}

Construtor não decide comportamento.


🚫 3️⃣ Código lento ou bloqueante

// ERRADO
public Service()
{
Thread.Sleep(3000);
}

Se o construtor é lento:

  • Startup lento
  • Timeout
  • Escalabilidade ruim

🚫 4️⃣ Código que pode falhar por causa externa

  • Rede
  • DNS
  • Credencial
  • Serviço terceiro

➡️ Isso pertence a métodos explícitos, não ao construtor.


🧠 Regra prática (memorável)

Se falhar, o construtor NÃO deve tentar resolver. Se precisar retry, não é construtor.


🧱 Tipos de construtores em C#

1️⃣ Construtor padrão (default)

public class Foo
{
public Foo() { }
}
  • Criado automaticamente se nenhum for definido
  • Não recebe parâmetros

2️⃣ Construtor parametrizado

public class Foo
{
public Foo(int value)
{
Value = value;
}
}
  • Mais comum
  • Ideal para dependências e invariantes

3️⃣ Construtor sobrecarregado

public class Foo
{
public Foo() : this(0) { }

public Foo(int value)
{
Value = value;
}
}
  • Evita duplicação
  • Um construtor principal

4️⃣ Construtor privado

public class Singleton
{
private Singleton() { }
}

Usado para:

  • Singleton
  • Factory methods
  • Controle de criação

5️⃣ Construtor estático

public class Config
{
static Config()
{
LoadDefaults();
}
}

Características:

  • Executa uma única vez
  • Antes do primeiro uso
  • Não recebe parâmetros

⚠️ Use com cuidado:

  • Difícil testar
  • Pode esconder falhas

6️⃣ Construtor em record

public record Product(Guid Id, string Name);
  • Imutável por padrão
  • Ideal para domínio e DTOs

7️⃣ Construtor com propriedades (init)

public class User
{
public string Name { get; init; }
}

Uso:

var user = new User { Name = "Ana" };

✔️ Imutabilidade parcial ✔️ Muito usado em DTOs


🧪 Construtores e Testes

Construtores bons:

  • Não precisam de mocks complexos
  • Não acessam infraestrutura
  • Criam objetos rapidamente

Se um construtor é difícil de testar → design suspeito.


📌 Padrão recomendado (resumo executivo)

✔️ Construtor:

  • valida
  • atribui
  • inicializa estado simples

❌ Construtor:

  • não conecta
  • não chama serviço
  • não executa lógica

➡️ Ação externa = método explícito


🎯 Exemplo final (padrão ideal)

public class RabbitMQConnectionManager
{
private readonly IConnectionFactory _factory;

public RabbitMQConnectionManager(IConnectionFactory factory)
{
_factory = factory;
}

public void AbrirConexao()
{
// aqui sim: retry, log, exceção, etc
}
}

🧠 Conclusão

Construtor não é lugar de esperteza. É lugar de segurança, previsibilidade e clareza.