Skip to main content

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:

checked faz o C# lançar uma OverflowException quando 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.

TipoAfetado pelo checked?
byteSim
sbyteSim
shortSim
ushortSim
intSim
uintSim
longSim
ulongSim
charSim, em conversões
decimalJá lança overflow por padrão
floatNão da mesma forma
doubleNã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-chaveComportamento
checkedLança OverflowException se houver overflow
uncheckedIgnora overflow e deixa o valor “estourar”
Nenhum dos doisDepende 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árioFaz sentido usar checked?
Cálculo financeiroSim
Contadores críticosSim
Conversão de long para intSim
Cálculo de quantidade de itensSim
Cálculo de limite, quota ou saldoSim
Código de baixo nível que depende de overflowNão
HashingNormalmente não
CriptografiaNormalmente não
Algoritmos que usam wraparound propositalNã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áticaRecomendação
Usar checked em cálculos críticosRecomendado
Usar checked em conversões perigosasRecomendado
Usar checked em todo código sem critérioDepende
Usar unchecked em hashingComum
Tratar OverflowException em bordas da aplicaçãoRecomendado
Deixar overflow silencioso em regra de negócioEvitar

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árioImpacto
Código comum de APINormalmente irrelevante
Cálculo de regra de negócioVale a segurança
Hot path extremoMedir antes
Loop massivo de baixo nívelPode impactar
Hashing/criptografiaGeralmente 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

PontoExplicação
checkedHabilita verificação de overflow
uncheckedDesabilita verificação de overflow
Exceção lançadaOverflowException
Principal usoCálculos inteiros e conversões numéricas
Mais útil emRegras de negócio, valores financeiros, limites, quantidades
Menos útil emHashing, 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;
}