🎓 Aulas de Programação Orientada a Objetos

Universo DC - Aprenda POO com exemplos práticos

Objetivo da Aula

Entender como tratar erros e exceções em C# usando Try-Catch, garantindo que o programa não trave quando algo der errado.

Aula 06: Try-Catch e Tratamento de Exceções


Conceito de Exceção

O que é uma Exceção?

Uma exceção é um evento que ocorre durante a execução do programa e interrompe o fluxo normal. Pode ser causada por:

Analogia: É como um acidente no trânsito. O Try-Catch é como um seguro que te ajuda a lidar com o problema sem parar tudo.

Estrutura Try-Catch

Sintaxe Básica

// TÓPICO: Estrutura Try-Catch
// 'try': Bloco onde colocamos código que pode gerar erro
try
{
    // Código que pode gerar exceção
    int resultado = 10 / 0;  // Divisão por zero causa exceção
}
// 'catch': Bloco que captura e trata a exceção
catch (Exception ex)
{
    // Código que executa se ocorrer exceção
    Console.WriteLine($"Erro: {ex.Message}");
}

Exemplo Prático: Sistema de Personagens

Exemplo 1: Divisão por Zero

// TÓPICO: Try-Catch Básico
public void CalcularForcaRelativa(Personagem personagem1, Personagem personagem2)
{
    try
    {
        // TÓPICO: Código que Pode Gerar Erro
        // Se personagem2.Nivel for 0, causa divisão por zero
        double forcaRelativa = personagem1.Nivel / personagem2.Nivel;
        Console.WriteLine($"Força relativa: {forcaRelativa}");
    }
    catch (Exception ex)
    {
        // TÓPICO: Tratamento do Erro
        // Captura qualquer exceção e exibe mensagem
        Console.WriteLine($"Erro ao calcular força: {ex.Message}");
    }
}

Exemplo 2: Conversão de Tipo

// TÓPICO: Try-Catch para Conversão
public void ProcessarNivel(string nivelTexto)
{
    try
    {
        // TÓPICO: Conversão que Pode Falhar
        // Se nivelTexto não for um número, causa exceção
        int nivel = int.Parse(nivelTexto);
        Console.WriteLine($"Nível convertido: {nivel}");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Erro ao converter nível: {ex.Message}");
    }
}

Try-Catch-Finally

Estrutura Completa

// TÓPICO: Try-Catch-Finally
try
{
    // Código que pode gerar exceção
    int resultado = 10 / 2;
    Console.WriteLine($"Resultado: {resultado}");
}
catch (Exception ex)
{
    // Executa se ocorrer exceção
    Console.WriteLine($"Erro: {ex.Message}");
}
finally
{
    // TÓPICO: Bloco Finally
    // SEMPRE executa, independente de ter erro ou não
    // Útil para limpeza de recursos (fechar arquivos, conexões, etc.)
    Console.WriteLine("Bloco finally sempre executa!");
}

Exemplo: Salvando Dados

// TÓPICO: Try-Catch-Finally com Recursos
public void SalvarPersonagem(Personagem personagem)
{
    // Simulando arquivo (em código real seria FileStream)
    bool arquivoAberto = false;

    try
    {
        arquivoAberto = true;
        Console.WriteLine($"Salvando {personagem.Nome}...");

        // Simulando erro
        if (personagem.Nome == null)
        {
            throw new Exception("Nome não pode ser nulo!");
        }

        Console.WriteLine("Salvo com sucesso!");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Erro ao salvar: {ex.Message}");
    }
    finally
    {
        // TÓPICO: Limpeza de Recursos
        // Sempre fecha o arquivo, mesmo se houver erro
        if (arquivoAberto)
        {
            Console.WriteLine("Fechando arquivo...");
            arquivoAberto = false;
        }
    }
}

Tipos Específicos de Exceções

Capturando Exceções Específicas

// TÓPICO: Múltiplos Catch (Exceções Específicas)
public void ProcessarPersonagem(string nome, string nivelTexto)
{
    try
    {
        // Validação
        if (string.IsNullOrEmpty(nome))
        {
            throw new ArgumentException("Nome não pode ser vazio!");
        }

        // Conversão
        int nivel = int.Parse(nivelTexto);

        // Divisão
        int forca = 100 / nivel;

        Console.WriteLine($"Personagem: {nome}, Nível: {nivel}, Força: {forca}");
    }
    // TÓPICO: Catch Específico para ArgumentException
    catch (ArgumentException ex)
    {
        Console.WriteLine($"Erro de argumento: {ex.Message}");
    }
    // TÓPICO: Catch Específico para FormatException
    catch (FormatException ex)
    {
        Console.WriteLine($"Erro de formato: {ex.Message}");
        Console.WriteLine("O nível deve ser um número válido!");
    }
    // TÓPICO: Catch Específico para DivideByZeroException
    catch (DivideByZeroException ex)
    {
        Console.WriteLine($"Erro de divisão: {ex.Message}");
        Console.WriteLine("Não é possível dividir por zero!");
    }
    // TÓPICO: Catch Genérico (Qualquer Outra Exceção)
    catch (Exception ex)
    {
        Console.WriteLine($"Erro inesperado: {ex.Message}");
    }
}

Tabela de Exceções Comuns

Tipo de ExceçãoQuando OcorreComo Aplicar
ExceptionExceção genérica (base de todas)catch (Exception ex) - Captura qualquer erro
ArgumentExceptionArgumento inválido passado para métodocatch (ArgumentException ex) - Validação de parâmetros
ArgumentNullExceptionArgumento nulo quando não deveria sercatch (ArgumentNullException ex) - Verificar null
FormatExceptionFormato de string inválidocatch (FormatException ex) - Conversão de tipos
DivideByZeroExceptionDivisão por zerocatch (DivideByZeroException ex) - Operações matemáticas
OverflowExceptionValor muito grande para o tipocatch (OverflowException ex) - Cálculos que excedem limite
IndexOutOfRangeExceptionÍndice fora dos limites do arraycatch (IndexOutOfRangeException ex) - Acesso a arrays/listas
NullReferenceExceptionTentativa de usar objeto nulocatch (NullReferenceException ex) - Verificar null antes de usar
FileNotFoundExceptionArquivo não encontradocatch (FileNotFoundException ex) - Operações com arquivos
InvalidOperationExceptionOperação inválida no estado atualcatch (InvalidOperationException ex) - Estados inconsistentes

Throw: Lançando Exceções

Throw New Exception

// TÓPICO: Lançar Exceção Manualmente
// Usamos 'throw' para lançar uma exceção quando detectamos um problema

public void ValidarPersonagem(Personagem personagem)
{
    // TÓPICO: Throw com Exception Genérica
    if (personagem == null)
    {
        throw new Exception("Personagem não pode ser nulo!");
    }

    // TÓPICO: Throw com ArgumentException
    if (string.IsNullOrEmpty(personagem.Nome))
    {
        throw new ArgumentException("Nome do personagem é obrigatório!");
    }

    // TÓPICO: Throw com ArgumentOutOfRangeException
    if (personagem.Nivel < 0)
    {
        throw new ArgumentOutOfRangeException("Nivel", personagem.Nivel,
            "Nível não pode ser negativo!");
    }

    // TÓPICO: Throw com InvalidOperationException
    if (personagem.Nivel > 100)
    {
        throw new InvalidOperationException("Nível máximo é 100!");
    }

    Console.WriteLine("Personagem válido!");
}

Exemplo: Throw em Métodos

// TÓPICO: Throw em Métodos de Classe
public class Heroi : Personagem
{
    public void SalvarVida()
    {
        // TÓPICO: Validação com Throw
        if (Nivel < 10)
        {
            throw new InvalidOperationException(
                "Herói precisa ter nível mínimo de 10 para salvar vidas!");
        }

        VidasSalvas++;
        Console.WriteLine($"{Nome} salvou uma vida!");
    }

    public void UsarPoderEspecial()
    {
        // TÓPICO: Throw com Mensagem Personalizada
        if (Nivel < 50)
        {
            throw new Exception(
                $"{Nome} precisa ter nível 50 ou superior para usar poder especial!");
        }

        Console.WriteLine($"{Nome} usa poder especial!");
    }
}

// TÓPICO: Usando Throw
try
{
    Heroi heroiNovato = new Heroi("Novato", 5, "Liga da Justiça");
    heroiNovato.SalvarVida();  // Lança exceção (nível muito baixo)
}
catch (InvalidOperationException ex)
{
    Console.WriteLine($"Erro: {ex.Message}");
}

Exemplo Completo: Sistema de Batalha com Try-Catch

// TÓPICO: Try-Catch em Sistema Completo
public class SistemaBatalha
{
    public static void IniciarBatalha(Personagem atacante, Personagem defensor)
    {
        try
        {
            // TÓPICO: Validações com Throw
            if (atacante == null)
            {
                throw new ArgumentNullException(nameof(atacante),
                    "Atacante não pode ser nulo!");
            }

            if (defensor == null)
            {
                throw new ArgumentNullException(nameof(defensor),
                    "Defensor não pode ser nulo!");
            }

            if (atacante.Nivel <= 0)
            {
                throw new ArgumentException("Nível do atacante deve ser maior que zero!");
            }

            // TÓPICO: Cálculo que Pode Gerar Erro
            int diferencaNivel = atacante.Nivel - defensor.Nivel;
            double chanceVitoria = 50.0 + (diferencaNivel * 2.0);

            // TÓPICO: Validação de Resultado
            if (chanceVitoria < 0)
            {
                throw new InvalidOperationException("Chance de vitória calculada incorretamente!");
            }

            Console.WriteLine($"=== BATALHA ===");
            Console.WriteLine($"{atacante.Nome} (Nível {atacante.Nivel}) vs " +
                            $"{defensor.Nome} (Nível {defensor.Nivel})");
            Console.WriteLine($"Chance de vitória de {atacante.Nome}: {chanceVitoria:F2}%");

            atacante.UsarPoder();
            defensor.UsarPoder();
        }
        // TÓPICO: Catch Específico para ArgumentNullException
        catch (ArgumentNullException ex)
        {
            Console.WriteLine($"Erro: Personagem não informado!");
            Console.WriteLine($"Detalhes: {ex.Message}");
        }
        // TÓPICO: Catch Específico para ArgumentException
        catch (ArgumentException ex)
        {
            Console.WriteLine($"Erro de validação: {ex.Message}");
        }
        // TÓPICO: Catch Específico para InvalidOperationException
        catch (InvalidOperationException ex)
        {
            Console.WriteLine($"Erro de operação: {ex.Message}");
        }
        // TÓPICO: Catch Genérico
        catch (Exception ex)
        {
            Console.WriteLine($"Erro inesperado: {ex.Message}");
            Console.WriteLine($"Tipo: {ex.GetType().Name}");
        }
        // TÓPICO: Finally para Limpeza
        finally
        {
            Console.WriteLine("Batalha finalizada.");
        }
    }
}

MessageBox.Show com Try-Catch

Explicação dos Parâmetros

// TÓPICO: MessageBox.Show - Parâmetros Explicados
try
{
    // Código que pode gerar erro
    SalvarPersonagem(batman);
}
catch (Exception ex)
{
    // TÓPICO: MessageBox.Show - Estrutura Completa
    // MessageBox.Show(mensagem, titulo, botoes, icone)

    MessageBox.Show(
        $"Erro ao salvar: {ex.Message}",  // Parâmetro 1: Mensagem (texto principal)
        "Erro",                            // Parâmetro 2: Título (barra de título)
        MessageBoxButtons.OK,             // Parâmetro 3: Botões (OK, YesNo, etc.)
        MessageBoxIcon.Error              // Parâmetro 4: Ícone (Error, Warning, Info, etc.)
    );
}

Parâmetros Detalhados

// TÓPICO: MessageBoxButtons - Tipos de Botões
MessageBox.Show("Mensagem", "Título", MessageBoxButtons.OK);           // Apenas OK
MessageBox.Show("Mensagem", "Título", MessageBoxButtons.OKCancel);     // OK e Cancelar
MessageBox.Show("Mensagem", "Título", MessageBoxButtons.YesNo);       // Sim e Não
MessageBox.Show("Mensagem", "Título", MessageBoxButtons.YesNoCancel); // Sim, Não e Cancelar
MessageBox.Show("Mensagem", "Título", MessageBoxButtons.RetryCancel);  // Tentar Novamente e Cancelar
MessageBox.Show("Mensagem", "Título", MessageBoxButtons.AbortRetryIgnore); // Abortar, Tentar, Ignorar

// TÓPICO: MessageBoxIcon - Tipos de Ícones
MessageBox.Show("Mensagem", "Título", MessageBoxButtons.OK, MessageBoxIcon.Error);      // ❌ Ícone de erro (vermelho)
MessageBox.Show("Mensagem", "Título", MessageBoxButtons.OK, MessageBoxIcon.Warning);    // ⚠️ Ícone de aviso (amarelo)
MessageBox.Show("Mensagem", "Título", MessageBoxButtons.OK, MessageBoxIcon.Information); // ℹ️ Ícone de informação (azul)
MessageBox.Show("Mensagem", "Título", MessageBoxButtons.OK, MessageBoxIcon.Question);   // ❓ Ícone de pergunta
MessageBox.Show("Mensagem", "Título", MessageBoxButtons.OK, MessageBoxIcon.None);      // Sem ícone

// TÓPICO: Capturando Resposta do MessageBox
DialogResult resultado = MessageBox.Show(
    "Deseja realmente excluir este personagem?",
    "Confirmar Exclusão",
    MessageBoxButtons.YesNo,
    MessageBoxIcon.Question
);

if (resultado == DialogResult.Yes)
{
    Console.WriteLine("Personagem excluído!");
}
else
{
    Console.WriteLine("Operação cancelada.");
}

Exemplo Completo com MessageBox

// TÓPICO: Try-Catch com MessageBox em Windows Forms
public void SalvarPersonagem(Personagem personagem)
{
    try
    {
        // Validação
        if (personagem == null)
        {
            throw new ArgumentNullException(nameof(personagem),
                "Personagem não pode ser nulo!");
        }

        if (string.IsNullOrEmpty(personagem.Nome))
        {
            throw new ArgumentException("Nome do personagem é obrigatório!");
        }

        // Simulação de salvamento
        Console.WriteLine($"Salvando {personagem.Nome}...");

        // Simulação de erro (em código real seria operação de arquivo)
        if (personagem.Nome == "Erro")
        {
            throw new Exception("Erro simulado ao salvar!");
        }

        // TÓPICO: MessageBox de Sucesso
        MessageBox.Show(
            $"Personagem '{personagem.Nome}' salvo com sucesso!",
            "Sucesso",
            MessageBoxButtons.OK,
            MessageBoxIcon.Information
        );
    }
    catch (ArgumentNullException ex)
    {
        // TÓPICO: MessageBox de Erro Específico
        MessageBox.Show(
            $"Erro: {ex.Message}\n\nPor favor, verifique os dados do personagem.",
            "Erro de Validação",
            MessageBoxButtons.OK,
            MessageBoxIcon.Warning
        );
    }
    catch (ArgumentException ex)
    {
        MessageBox.Show(
            $"Erro de validação: {ex.Message}",
            "Erro",
            MessageBoxButtons.OK,
            MessageBoxIcon.Error
        );
    }
    catch (Exception ex)
    {
        // TÓPICO: MessageBox de Erro Genérico
        MessageBox.Show(
            $"Erro ao salvar: {ex.Message}\n\nTipo: {ex.GetType().Name}",
            "Erro",
            MessageBoxButtons.OK,
            MessageBoxIcon.Error
        );
    }
}

Boas Práticas

  1. Sempre use Try-Catch em operações que podem falhar (arquivos, rede, conversões)
  2. Capture exceções específicas primeiro, depois a genérica
  3. Use Finally para limpeza de recursos
  4. Não ignore exceções - sempre trate ou registre
  5. Use Throw para validar dados e lançar exceções apropriadas
  6. Mensagens claras - ajude o usuário a entender o erro

Resumo

Próxima Aula

Na próxima aula, veremos Encapsulamento e modificadores de acesso (public, private, protected).