Regra de ouro: Use exceptions para sinalizar condicoes inesperadas e excepcionais β€” nunca para controle de fluxo normal. Prefira exceptions especificas (ArgumentNullException, InvalidOperationException) e valide cedo com guard clauses. Sempre faca cleanup em finally / using / await using.

Hierarquia de Exceptions no .NET

ExceptionSystemExceptionApplicationExceptionArgumentExceptionInvalidOperation ExceptionNullReference ExceptionArgumentNull ExceptionArgumentOutOf RangeException

Try / Catch / Finally β€” mecanica basica

O bloco try delimita codigo que pode falhar. catch captura exceptions especificas. finally executa sempre β€” sucesso ou falha β€” ideal para cleanup.

// Try/Catch/Finally β€” mecanica basica try { DoWork(); } catch (IOException ex) { Console.Error.WriteLine($"I/O failed: {ex.Message}"); // maybe retry, maybe surface to caller } finally { Console.WriteLine("Always runs (cleanup/logging)."); }

Ordem dos catches: especifico antes de generico

Ordene catches do mais especifico para o mais generico. Exception filters com when permitem branching por propriedades da exception sem if aninhados. O filtro roda antes do handler executar.

// Ordene catches do mais especifico para o mais generico // Filters com 'when' permitem branching sem if aninhado try { SaveFile(path); } catch (IOException ex) when (IsTransient(ex)) { Console.Error.WriteLine("Transient I/Oβ€”retrying once..."); SaveFile(path); // simplistic single retry } catch (IOException ex) { Console.Error.WriteLine($"Non-transient I/O: {ex.Message}"); throw; // rethrow preserving stack }

throw vs throw ex β€” preservar stack trace

Use throw; para re-lancar preservando o stack trace original. throw ex; reseta o stack trace para o ponto atual, dificultando diagnostico.

// throw; preserva stack trace original // throw ex; reseta stack trace β€” EVITE try { Dangerous(); } catch (Exception ex) { Log(ex); throw; // preserves original stack trace // throw ex; // resets stack trace to this point β€” BAD }

Quando lancar vs quando capturar

SituacaoAcaoPor que
Argumento invalidothrow imediatamenteFail fast β€” nao deixe estado corrompido propagar
Erro transiente (I/O, rede)catch + retryPode se recuperar com nova tentativa
Erro numa boundary (API, service)catch + wrapTraduz para exception de dominio com contexto
Erro que voce nao sabe tratarDeixe propagarAlguem acima sabe; nao engula silenciosamente
Cancelamento (OperationCanceledException)Propague ou trate distinctamenteNao e erro β€” e cooperacao. Nao wrape como falha
throw vs throw ex?
throw; preserva o stack trace original intacto β€” voce ve exatamente onde a exception originou. throw ex; reseta o stack trace para o ponto do rethrow, destruindo a informacao da origem. Sempre use throw; a menos que intencionalmente queira esconder a origem (raro). Em .NET 6+, ExceptionDispatchInfo.Throw(ex) e outra opcao que preserva tudo.
Quando capturar vs deixar exceptions propagarem?
Capture apenas se voce pode fazer algo util: retry, wrap com contexto, traduzir para resposta HTTP, ou logar e re-lancar. Se nao sabe o que fazer, deixe propagar β€” um handler mais acima (middleware, global handler) vai tratar. Engolir exceptions (catch { } vazio) e um dos piores antipatterns: esconde bugs e corrompe estado silenciosamente.