C# - Criando exceções personalizadas


  Hoje veremos como criar exceções personalizadas usando a linguagem C#.

Uma exceção é uma condição de erro ou um comportamento inesperado que ocorre durante a execução de um código em um programa.

Na linguagem C# uma exceção pode ser definida como um objeto que herda da classe System.Exception que é criado ou lançado quando ocorre uma condição de erro e que contém informações que devem ajudar a identificar o problema ocorrido.

Ao ocorrer uma exceção ela é lançada da área do código onde ocorreu o problema e passada para cima na pilha de chamadas de método em execução até que seja tratada ou que o programa seja encerrado.

A plataforma .NET inclui classes de exceção internas para cada erro possível, e, a classe Exception é a classe base de todas as classes de exceção.

A seguir temos a hierarquia de classes de exceções (resumida) do .NET :


No entanto, em alguns casos, quando nenhuma delas atende às nossas necessidades, podemos criar nossas próprias exceções personalizadas derivando da classe Exception. Desta forma para criar uma classe de exceção personalizada basta criar a sua classe derivando da classe System.Exception, e, isso é bem fácil de ser implementado.

Basta seguir duas recomendações :

1 - A recomendação é finalizar o nome da exceção criada com a palavra "Exception"
2 - Implementar os três construtores comuns


A seguir temos um exemplo de uma classe de exceção personalizada chamada MinhaExcecaoException
que herda de Exception :

public class MinhaExcecaoException : Exception
{
  public MinhaExcecaoException()
  { }

  public MinhaExcecaoException(string message)
  : base(message)
  { }

  public MinhaExcecaoException(string message, Exception inner)
  : base(message, inner)
  { }
}

Observe que o nome da exceção termina com o sufixo Exception e que ela implementa os 3 construtores :

  1. O construtor sem parâmetros
  2. O construtor usando o parâmetro message
  3. O construtor usando o parâmetro message e um tipo Exception

Após criar a classe de exceção personalizada podemos usar a classe da mesma forma que usamos uma classe de exceção da plataforma .NET e assim podemos então em um bloco try-catch e lançar a exceção usando a instrução throw e no bloco catch capturar a exceção da mesma forma que fazemos com qualquer outra exceção.

Para o exemplo acima podemos então fazer o tratamento de erros assim:

try
{
    //codigo
    throw new MinhaExcecaoException("Esta é a minha exceção");
}
catch (MinhaExcecaoException ex)
{
   Console.WriteLine(ex.Message);
   Console.WriteLine(ex.StackTrace);
}

Como exemplo vamos criar um projeto Console no .NET 7.0 e criar uma classe Conta com 3 propriedades: Numero, Titular e Saldo e os métodos Depositar e Sacar :

public class Conta
{
   public Conta(int numero, string? titular, decimal saldo)
   {
      Numero = numero;
      Titular = titular;
      Saldo = saldo;
   }

    public int Numero { get; set; }
    public string? Titular { get; set;}
    public decimal Saldo { get; set; }

   public decimal Depositar(decimal valor)
   {
      Saldo += valor;
      Console.WriteLine($"Depositou : {valor}");
     return Saldo;
   }
   public decimal Sacar(decimal valor)
   {
      Console.WriteLine($"Sacou : {valor}");

      if (Saldo < valor)
      throw new ArgumentException("Saldo Insuficiente");


      Saldo -= valor;
      return Saldo;
   }

    public override string ToString() => $"Conta : {Numero} : {Titular} - Saldo={Saldo}\n";
}

Note que aqui estamos lançando um ArgumentoException, que é um exceção da plataforma .NET, quando o valor do saque for maior que o saldo.

Vamos agora criar uma classe no projeto personalizada chamada SaldoInsuficienteExcepton para tratar esta exceção de forma específica.

public class SaldoInsuficienteException : Exception
{
    public SaldoInsuficienteException() { }

    public SaldoInsuficienteException(string? message)
        : base(message)
    { }
    public SaldoInsuficienteException(string? message, Exception? innerException)
        : base(message, innerException)
    { }
    public SaldoInsuficienteException(decimal saque, decimal saldo)
      : base($"\nException: Valor do saque {saque} é superior ao saldo {saldo}")
    { }
    public override string HelpLink
    {
        get
        {
            return "Info: https://rb.gy/clgqbv";
        }
   }
}

Neste código criamos a exceção personalizada que herda de Exception e que implementa os construtores padrão. Para incrementar um pouco o código implementamos um construtor que vai receber os argumentos do valor do saque e do saldo e exibir uma mensagem ao usuário.

Também sobrescrevemos a propriedade HelpLink definindo um link de ajuda para a exceção.

Para usar esta implementação vamos alterar o código da classe Program e implementar o tratamento de erros tratando a exceção SaldoInsuficienteException em um bloco try-catch:

using _06ExcecoesPersonalizadas;
Conta conta1 = new Conta(100, "Maria", 100m);
try
{
    Console.WriteLine(conta1.ToString());
    conta1.Depositar(100);
    Console.WriteLine($"Saldo : {conta1.Saldo}");
    conta1.Sacar(300);
    Console.WriteLine($"Saldo : {conta1.Saldo}");
}
catch(SaldoInsuficienteException ex)
{
    Console.WriteLine(ex.Message);
    Console.WriteLine(ex.HelpLink);
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
    Console.WriteLine(ex.StackTrace);
}
Console.ReadKey();
public class Conta
{
    public Conta(int numero, string? titular, decimal saldo)
    {
        Numero = numero;
        Titular = titular;
        Saldo = saldo;
    }
    public int Numero { get; set; }
    public string? Titular { get; set; }
    public decimal Saldo { get; set; }
    public decimal Depositar(decimal valor)
    {
        Saldo += valor;
        Console.WriteLine($"Depositou : {valor}");
        return Saldo;
    }
    public decimal Sacar(decimal valor)
    {
        Console.WriteLine($"Sacou : {valor}");       
        if (Saldo < valor)
            throw new SaldoInsuficienteException(valor,Saldo);
        Saldo -= valor;
        return Saldo;
    }

    public override string ToString()
    {
        return $"Conta : {Numero} : {Titular} - Saldo={Saldo}";
    }
}

 

Note que agora extamos lançando a exceção SaldoInsuficienteException usando a instrução throw e que estamos usando o construtor passando o valor do saque e do saldo.

Executando o código iremos obter o seguinte resultado no console:

Podemos ainda sobrescrever a propriedade Message da classe Exception em nossa exceção personalizada :

...
  public
override string Message
  {
   
get
    {
       
return "\nNão existe saldo suficiente para o valor do saque";
    }
  }
...

Para concluir seguem algumas recomendações importantes a considerar quando da criação de uma exceção personalizada :

E estamos conversados...

 "Todas as coisas são puras para os puros, mas nada é puro para os contaminados e infiéis; antes o seu entendimento e consciência estão contaminados."
Tito 1:15

Referências:


José Carlos Macoratti