checked | CSharp
- checked | CSharp
checked no C#
checked é uma palavra-chave do C# usada para habilitar verificação de overflow aritmético em operações com tipos numéricos integrais.
Em termos práticos:
checkedfaz o C# lançar umaOverflowExceptionquando uma operação aritmética ultrapassa o limite permitido pelo tipo.
Problema que o checked resolve
Tipos numéricos têm limites.
Exemplo:
int valorMaximo = int.MaxValue;
Console.WriteLine(valorMaximo);
// 2147483647
Se você somar 1 nesse valor:
int resultado = int.MaxValue + 1;
O resultado matemático correto seria:
2147483648
Mas esse valor não cabe em um int, porque int vai até:
2147483647
Sem verificação de overflow, o valor pode “virar” para o outro lado do intervalo.
Exemplo sem checked
int valor = int.MaxValue;
int resultado = valor + 1;
Console.WriteLine(resultado);
Resultado provável:
-2147483648
Isso acontece porque houve overflow.
O valor passou do limite máximo do int e retornou para o limite mínimo.
Exemplo com checked
int valor = int.MaxValue;
int resultado = checked(valor + 1);
Console.WriteLine(resultado);
Resultado:
System.OverflowException
Agora o C# detecta o overflow e lança exceção.
Forma 1: checked como expressão
Você pode aplicar checked diretamente em uma expressão.
int a = int.MaxValue;
int b = 1;
int resultado = checked(a + b);
Nesse caso, apenas a expressão dentro do checked(...) terá verificação de overflow.
Forma 2: checked como bloco
Você também pode usar checked em um bloco de código.
checked
{
int a = int.MaxValue;
int b = 1;
int resultado = a + b;
Console.WriteLine(resultado);
}
Tudo dentro do bloco será avaliado com verificação de overflow.
Forma 3: checked com cast explícito
Um caso muito comum é conversão entre tipos numéricos.
long valor = long.MaxValue;
int convertido = checked((int)valor);
Como long.MaxValue não cabe em um int, isso lança:
System.OverflowException
Sem checked, o valor seria truncado ou convertido de forma incorreta.
Exemplo sem checked em conversão
long valor = long.MaxValue;
int convertido = (int)valor;
Console.WriteLine(convertido);
Resultado possível:
-1
Isso é perigoso, porque o programa continua executando com um valor inválido do ponto de vista do negócio.
Exemplo com checked em conversão
long valor = long.MaxValue;
int convertido = checked((int)valor);
Console.WriteLine(convertido);
Resultado:
System.OverflowException
Tipos afetados pelo checked
O checked afeta principalmente operações com tipos integrais.
| Tipo | Afetado pelo checked? |
|---|---|
byte | Sim |
sbyte | Sim |
short | Sim |
ushort | Sim |
int | Sim |
uint | Sim |
long | Sim |
ulong | Sim |
char | Sim, em conversões |
decimal | Já lança overflow por padrão |
float | Não da mesma forma |
double | Não da mesma forma |
checked com int
checked
{
int x = int.MaxValue;
int y = x + 1;
}
Lança:
OverflowException
checked com byte
checked
{
byte valor = 255;
byte resultado = (byte)(valor + 1);
}
Lança:
OverflowException
O byte aceita valores de 0 até 255.
checked com decimal
O decimal já lança exceção em overflow, mesmo sem checked.
decimal valor = decimal.MaxValue;
decimal resultado = valor + 1;
Isso já gera erro de overflow.
Nesse caso, checked não muda muito o comportamento.
checked com float e double
float e double seguem regras diferentes.
Eles normalmente não lançam OverflowException com checked.
Exemplo:
double valor = double.MaxValue;
double resultado = valor * 2;
Console.WriteLine(resultado);
Resultado:
Infinity
Ou seja, para double e float, overflow geralmente vira Infinity, e não exceção.
unchecked
O oposto de checked é unchecked.
Ele força o C# a não verificar overflow.
int valor = int.MaxValue;
int resultado = unchecked(valor + 1);
Console.WriteLine(resultado);
Resultado:
-2147483648
Diferença entre checked e unchecked
| Palavra-chave | Comportamento |
|---|---|
checked | Lança OverflowException se houver overflow |
unchecked | Ignora overflow e deixa o valor “estourar” |
| Nenhum dos dois | Depende da configuração do compilador/contexto |
Contexto padrão do C#
Por padrão, operações aritméticas com variáveis inteiras geralmente são executadas em contexto unchecked.
Exemplo:
int x = int.MaxValue;
int y = x + 1;
Console.WriteLine(y);
Normalmente resulta em:
-2147483648
Mas existe uma exceção importante: expressões constantes podem gerar erro em tempo de compilação.
Overflow em constante
int resultado = int.MaxValue + 1;
Esse código pode gerar erro de compilação, porque o compilador consegue calcular o valor em tempo de compilação e detectar o overflow.
Erro típico:
CS0220: The operation overflows at compile time in checked mode
Agora compare com:
int valor = int.MaxValue;
int resultado = valor + 1;
Aqui o cálculo acontece em tempo de execução.
Exemplo prático com regra de negócio
Imagine um sistema que soma quantidade de itens processados.
public static int SomarQuantidade(int atual, int incremento)
{
return checked(atual + incremento);
}
Uso:
int total = int.MaxValue;
int novoTotal = SomarQuantidade(total, 1);
Resultado:
OverflowException
Isso é melhor do que deixar o total virar negativo silenciosamente.
Exemplo prático em API
app.MapPost("/calcular-total", (CalculoRequest request) =>
{
try
{
int total = checked(request.Quantidade * request.PrecoUnitario);
return Results.Ok(new
{
total
});
}
catch (OverflowException)
{
return Results.BadRequest(new
{
erro = "O cálculo ultrapassou o limite numérico permitido."
});
}
});
public sealed record CalculoRequest(
int Quantidade,
int PrecoUnitario);
Nesse exemplo, se a multiplicação ultrapassar o limite de int, a API retorna erro controlado.
Exemplo com dinheiro
Para dinheiro, o ideal normalmente é usar decimal, não int, float ou double.
decimal preco = 9999999999999999999999999999m;
decimal quantidade = 10m;
decimal total = checked(preco * quantidade);
O decimal já é mais adequado para valores financeiros e também trabalha melhor com overflow nesse tipo de cenário.
Onde faz sentido usar checked
Use checked quando o overflow pode gerar dado inválido ou comportamento perigoso.
Exemplos:
| Cenário | Faz sentido usar checked? |
|---|---|
| Cálculo financeiro | Sim |
| Contadores críticos | Sim |
Conversão de long para int | Sim |
| Cálculo de quantidade de itens | Sim |
| Cálculo de limite, quota ou saldo | Sim |
| Código de baixo nível que depende de overflow | Não |
| Hashing | Normalmente não |
| Criptografia | Normalmente não |
| Algoritmos que usam wraparound proposital | Não |
Onde não usar checked
Não use checked quando o overflow é intencional.
Exemplo clássico: algoritmos de hash.
unchecked
{
int hash = 17;
hash = hash * 31 + nome.GetHashCode();
hash = hash * 31 + idade.GetHashCode();
return hash;
}
Nesse tipo de código, o overflow faz parte da estratégia.
Por isso, unchecked é comum em implementação de GetHashCode.
checked em projeto inteiro
Também é possível habilitar verificação de overflow no projeto.
No .csproj:
<PropertyGroup>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
Com isso, operações aritméticas inteiras passam a ser verificadas de forma mais ampla.
Exemplo:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
</Project>
Exemplo comparando configuração global
Com:
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
Este código:
int valor = int.MaxValue;
int resultado = valor + 1;
passa a lançar:
OverflowException
Sem essa configuração, normalmente o resultado seria:
-2147483648
checked em método inteiro
Você pode envolver o corpo inteiro de um método:
public static int Calcular(int quantidade, int preco)
{
checked
{
int total = quantidade * preco;
return total;
}
}
Ou aplicar apenas onde importa:
public static int Calcular(int quantidade, int preco)
{
return checked(quantidade * preco);
}
A segunda forma é mais objetiva quando só existe uma operação crítica.
Boas práticas
| Prática | Recomendação |
|---|---|
Usar checked em cálculos críticos | Recomendado |
Usar checked em conversões perigosas | Recomendado |
Usar checked em todo código sem critério | Depende |
Usar unchecked em hashing | Comum |
Tratar OverflowException em bordas da aplicação | Recomendado |
| Deixar overflow silencioso em regra de negócio | Evitar |
Exemplo completo
using System;
public static class Program
{
public static void Main()
{
try
{
int quantidade = int.MaxValue;
int incremento = 1;
int total = checked(quantidade + incremento);
Console.WriteLine(total);
}
catch (OverflowException)
{
Console.WriteLine("Overflow detectado.");
}
}
}
Saída:
Overflow detectado.
Exemplo completo com unchecked
using System;
public static class Program
{
public static void Main()
{
int quantidade = int.MaxValue;
int incremento = 1;
int total = unchecked(quantidade + incremento);
Console.WriteLine(total);
}
}
Saída:
-2147483648
Diferença visual
int valor = int.MaxValue;
Console.WriteLine(unchecked(valor + 1)); // -2147483648
Console.WriteLine(checked(valor + 1)); // OverflowException
Relação com performance
checked pode adicionar uma pequena sobrecarga, porque o runtime precisa verificar se a operação ultrapassou o limite.
Na prática:
| Cenário | Impacto |
|---|---|
| Código comum de API | Normalmente irrelevante |
| Cálculo de regra de negócio | Vale a segurança |
| Hot path extremo | Medir antes |
| Loop massivo de baixo nível | Pode impactar |
| Hashing/criptografia | Geralmente evitar |
Para API, regra de negócio e validação de dados, a segurança costuma ser mais importante que a micro-otimização.
Exemplo em hot path
Evite usar checked sem necessidade em loops muito intensivos:
checked
{
for (int i = 0; i < 10_000_000; i++)
{
soma += i;
}
}
Se esse trecho estiver em um caminho extremamente sensível de performance, o ideal é medir com BenchmarkDotNet antes de decidir.
Quando eu usaria no dia a dia
Eu usaria checked principalmente em:
int total = checked(quantidade * valorUnitario);
int tamanho = checked((int)arquivo.Length);
int novoLimite = checked(limiteAtual + incremento);
int totalProcessado = checked(processados + novosItens);
Quando eu evitaria
Eu evitaria em:
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 31 + Id.GetHashCode();
hash = hash * 31 + Nome.GetHashCode();
return hash;
}
}
Nesse caso, overflow é aceitável e esperado.
Resumo direto
| Ponto | Explicação |
|---|---|
checked | Habilita verificação de overflow |
unchecked | Desabilita verificação de overflow |
| Exceção lançada | OverflowException |
| Principal uso | Cálculos inteiros e conversões numéricas |
| Mais útil em | Regras de negócio, valores financeiros, limites, quantidades |
| Menos útil em | Hashing, algoritmos que dependem de wraparound |
| Pode ser global? | Sim, via .csproj |
Afeta float/double? | Não da mesma forma |
Afeta decimal? | decimal já tende a lançar overflow |
Regra prática
Use checked quando um valor errado for pior do que uma exceção.
Exemplo:
int total = checked(quantidade * preco);
Use unchecked quando o overflow fizer parte do algoritmo.
Exemplo:
unchecked
{
hash = hash * 31 + valor;
}