Skip to main content

Guard Clauses | CSharp

  • Guard Clauses | CSharp

Pacote com a mesma ideia: 🔗 Clique aqui


O que são Guard Clauses?

Guard Clauses são verificações rápidas no início de métodos, construtores ou propriedades para garantir que os argumentos e o estado do objeto são válidos. Quando uma condição inválida é detectada, uma exceção é lançada imediatamente, evitando:

  • Fluxos de código profundamente aninhados (if dentro de if)
  • Estados inválidos difíceis de depurar
  • Erros silenciosos que aparecem mais tarde

No .NET moderno (especialmente a partir do .NET 7 e com melhorias no .NET 8), a plataforma fornece métodos auxiliares (helpers) embutidos para escrever Guard Clauses de forma mais clara, concisa e consistente.


Por que usar Guard Clauses?

  • 📌 Código mais legível
  • 📌 Falhas rápidas (fail fast)
  • 📌 Menos if espalhados pelo método
  • 📌 Exceções padronizadas pelo próprio framework

Exemplo clássico (antes):

if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value));
}

Com Guard Clause (depois):

ArgumentOutOfRangeException.ThrowIfNegative(value);

Guard Clauses embutidas no .NET 7 e .NET 8

Validações de null e strings

Disponíveis no .NET 7 e 8:

ArgumentNullException.ThrowIfNull(obj);
ArgumentException.ThrowIfNullOrEmpty(texto);
ArgumentException.ThrowIfNullOrWhiteSpace(texto);

Esses métodos:

  • Usam automaticamente nameof(parametro)
  • Geram exceções consistentes
  • Reduzem código repetitivo

Novidades do .NET 8: Guard Clauses Numéricas

No .NET 8, várias Guard Clauses foram adicionadas para tipos numéricos genéricos, usando INumber<T>.

Exemplos disponíveis

ArgumentOutOfRangeException.ThrowIfGreaterThan(valor, limite);
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(valor, limite);
ArgumentOutOfRangeException.ThrowIfLessThan(valor, limite);
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(valor, limite);

ArgumentOutOfRangeException.ThrowIfZero(valor);
ArgumentOutOfRangeException.ThrowIfNegative(valor);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(valor);

Requisitos

Esses métodos funcionam com tipos que implementam:

where TValue : INumber<TValue>

Ou seja, funcionam com:

  • int
  • long
  • float
  • double
  • decimal
  • entre outros

Exemplo prático com método

public void Sacar(decimal valor)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(valor);

// lógica de saque
}

Resultado:

  • Código mais curto
  • Intenção clara
  • Menos erros

Novidade do .NET 8: Guard para objetos descartados (Dispose Helper)

Uma melhoria importante no .NET 8 é a simplificação da verificação de objetos já descartados (disposed).

Antes (.NET 7 ou anterior)

public class MyClass : IDisposable
{
private bool isDisposed;

public void DoAction()
{
if (isDisposed)
throw new ObjectDisposedException(nameof(MyClass));
}

public void Dispose()
{
isDisposed = true;
}
}

Depois (.NET 8)

public class MyClass : IDisposable
{
private bool isDisposed;

public void DoAction()
{
ObjectDisposedException.ThrowIf(isDisposed, this);
}

public void Dispose()
{
isDisposed = true;
}
}

Benefícios

  • ✔ Menos código
  • ✔ Exceção mais consistente
  • ✔ Melhor experiência para mantenedores de bibliotecas

Boas práticas ao usar Guard Clauses

  • Coloque sempre no início do método
  • Use Guard Clauses para validar entradas, não regras de negócio complexas
  • Prefira os helpers do framework em vez de exceções manuais
  • Não exagere: validações simples e diretas

Quando NÃO usar Guard Clauses

  • Para regras de negócio complexas
  • Quando o fluxo depende de múltiplas condições encadeadas
  • Quando uma exceção não é o comportamento esperado