Gerenciando Exceções em Aplicações .Net

by Felipe Oriani 7. September 2009 19:13

 

Olá pessoal, hoje vamos tratar de um assunto relacionado a tratamento de erros em aplicações .Net, no qual é muito importante para garantir a consistência da informação em certos momentos da execução e utilização de um software, seja na manutenção do código fonte, seja durante o desenvolvimento, em ambientes de testes e até mesmo em definição de regras de negócio que a aplicação deve atender.

Existem inúmeras classes no .Net Framework que são utilizadas para o tratamento de exceções (erros). Algumas destas classes já contem definições para um determinado tipo de exceção, como por exemplo, a classe FileNotFoundException que é disparada pelo .Net Framework quando a aplicação .Net tenta acessar um arquivo inexistente em disco. Estas classes já existentes para o tratamento de exceções no .Net Framework derivam de uma classe base chamada Exception, que contém uma definição bases para todo e qualquer tipo de erro/exceção que possa ocorrer durante a execução de uma aplicação .Net, seja web, windows forms ou distribuída.

Tratando exceções durante a execução.

Quando temos um bloco de código que sabemos que pode ocorrer uma exceção, devemos prevenir esta execução com o bloco try/catch/finally. Um código que é colocado entre este bloco, é determinado a tentar executar tal tarefa, e caso ocorra um erro é permitido que se trate o erro e tenha maior controle durante a execução. A listagem 1, exibe um exemplo de como o .Net Framework trata a execução dentre este bloco apresentado:

try

{

    //tenta executar um código

}

catch (Exception ex)

{

    //caso ocorra um erro, a execução irá entrar no bloco catch

    string mensagem = ex.Message;

}

finally

{

    //indepentende se ocorreu erro ou não,

    // este bloco é executado para finalização

}

Listagem 1: Bloco Try/Catch/Finally

Conforme a listagem 1 a execução que entra em um bloco try/catch/finally, entra no scopo do bloco try e executa o código, caso ocorra um erro, ela irá passar pelo scopo do bloco catch (perceba que resgatamos a exceção na declaração do bloco catch, e é aqui que podemos definir o tipo de exceção) e por fim , independentemente se ocorreu uma exceção ou não, é executado o bloco finally. Este último bloco finally, é opcional. Outro detalhe importante, é que esta estrutura de execução permite que coloquemos vários blocos catch, ou seja, podemos definir o tipo de exceção na declaração de vários blocos catch. Vale lembrar também que a execução de uma exceção em um bloco try/catch irá entrar no primeiro catch para qual a exceção disparada for cabível, ou seja, recomenda-se que o desenvolvedor especifique a declaração do bloco try/catch do tipo de exceção mais específica para a mais genérica. A listagem 2, exibe um exemplo para uma operação com arquivos:

 

try

{

    //tenta executar uma operação de IO

}

catch (FileNotFoundException ex)

{

    //caso o arquivo não tenha sido encontrado            

}

catch (FieldAccessException ex)

{

    //caso o arquivo não esteja acessível

}

catch (IOException ex)

{

    //erro geral no sistema de arquivos

}

catch (Exception ex)

{

    //erro geral na execução

}

finally

{

    //finalização de streams

}

Listagem 2: Demonstração de execução de blocos try/catch/finally

Como podemos ver no exemplo acima, temos quatro possíveis erros na execução deste código no qual executa uma operação de IO.

Criando as nossas exceções

Podemos também ter, além disso, nossas próprias exceções customizadas, mantendo informações personalizadas a respeito de o erro em questão. Por exemplo, um cliente que deseja fazer uma compra em um sistema de comércio e este está com pendências em haver com o setor financeiro da companhia. Podemos tratar estes problemas criando uma classe que derive de Exception e armazene informações do cliente para identificação durante a execução. A listagem 3 exibe um exemplo de uma classe customizada para o tratamento desta exceção.

public class ClienteDevendoException : Exception

{

    private Cliente _cliente;

    public Cliente Cliente

    {

        get { return _cliente; }

    }

 

    public ClienteDevendoException(int Id)

        : base("Cliente está com pendências no setor finânceiro. Favor verificar.")

    {

        _cliente = new Cliente(Id);

    }

 

    public ClienteDevendoException(Cliente cliente)

        : base(String.Format("O Cliente {0} está com pendências no setor finânceiro. Favor verificar.", cliente.Nome))

    {

        _cliente = cliente;

    }

}

Listagem 3: Criação de uma classe de exceção customizada.

Como podemos notar, a classe deriva de Exception que é a classe base e contém algumas customizações, como a mensagem de erro, e um objeto interno contendo a representação do cliente, sendo que em seu construtor ele pode receber um objeto do tipo Cliente ou o próprio Id do cliente.  Note também que a classe contém em seu nome o prefixo Exception, na qual é uma boa prática na nomeação de classes com esta finalidade, outro exemplo seria uma compra na qual o caixa não contém crédito suficiente, por exemplo: “CreditoInsuficienteException”.

Disparando exceções

Além de poder recuperar exceções durante a execução, podemos também dispará-las caso alguma informação seja executada incorretamente, como por exemplo, as regras de negócio de uma aplicação. Seguindo o exemplo anterior, nas regras de negócio de uma aplicação comercial um cliente não pode realizar uma compra caso contenha pendências com o setor financeiro da empresa, então podemos desenvolver uma execução como a listagem 4, disparando a exceção caso a condição não atenda aos quesitos.

if (ContemPendenciasFinanceiras(Cliente.Id))

{

    throw new ClienteDevendoException(Cliente);

}

 

Listagem 4: Disparando uma exceção.

Como podemos notar, utilizando a palavra-chave “throw”, podemos lançar a exceção para a execução da aplicação e interromper a execução do método no qual está realizando esta operação de venda e impedir que ela ocorra.

Da mesma forma que recuperamos a exceções no exemplo com operações de IO, podemos recuperar esta exceção customizada, veja na listagem 5.

try

{

    Venda venda = new Venda();

   

    foreach(VendaItem item in Itens)

    {

        venda.Items.Add(item);

    }

 

    venda.Cliente = new Cliente(IdCliente);

   

    venda.Finalizar();                    

 

    venda.ImprimirNotaFiscal();

}

catch(ClienteDevendoException ex)

{

    //cliente com pendencias

}

catch(Exception ex)

{

    //erros gerais

}

finally

{

 

}

Listagem 5: Execução e recuperação de exceção customizada.

Como podemos notar no exemplo, temos a execução de uma camada de aplicação simples na qual trata a criação de uma venda com o Cliente contendo pendências e erros comuns que possam ocorrer durante a execução com o bloco Exception.

Recomendações

Não tente utilizar o bloco try/catch para realizar tarefas que você tem certeza que possa ocorrer o erro e definir o valor de uma variável de retorno de funções.

Bem pessoal isso é tudo. Espero que tenha conseguido demonstrado de forma fácil como tratar e gerenciar melhor a execução de uma aplicação .Net.

Um abraço

 

Tags:

.Net Framework

Comments

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen

Sobre

Sou Felipe Oriani e trabalho com desenvolvimento web desde 2004, com tecnologias Microsoft como Asp e Asp.Net utilizando as linguagens C# e Vb.Net. Bacharel em Ciência da Computação pela Escola de Engenharia de Piracicaba,  MCP (Microsoft Certified Professional) e lider da comunidade C# Brasil. Conheça um pouco mais sobre meu Currículum.

Selos

C# Brasil