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 (
ifdentro deif) - 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
ifespalhados 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:
intlongfloatdoubledecimal- 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