Clique aqui para ler todos os artigos desta edição
Tratamento de erros em .NET
por Marden Menezes
Um dos fantasmas que perseguem os desenvolvedores durante o desenvolvimento são os erros que ocorrem no programa. Se houver algum erro na escrita do código ou se quisermos, por exemplo, executar um método que ainda não tenha sido criado, o compilador nos avisará desse erro e nós poderemos consertá-lo antes de executar o programa. São os chamados erros “em tempo de compilação”. E quando os erros acontecem no momento em que o programa está sendo executado (os chamados erros “em tempo de execução”), o que fazemos?
A plataforma .NET oferece uma maneira estruturada de gerenciar e tratar erros através do mecanismo de Exceptions.
O que são Exceptions?
Exceptions são uma maneira estruturada e orientada a objetos de representar os erros. Esse mecanismo representa os erros como objetos e baseia-se em uma classe base chamada System.Exception, da qual derivam por herança todas as outras Exceptions. Veja algumas propriedades que a classe Exception oferece para facilitar o gerenciamento e reconhecimento de erros:
Propriedade |
Descrição |
Message |
Propriedade somente leitura que contém um texto descritivo do erro. |
InnerException |
Caso a exceção tenha sido causada por outra exceção, essa propriedade retorna a referência a ela. |
Source |
O nome da aplicação ou do objeto que causou o erro. |
StackTrace |
Uma string que representa as chamadas da pilha no momento em que a exceção foi lançada. |
Você pode criar uma Exception que herde a classe de qualquer outra Exception já existente no .NET, por exemplo, Exception, DivideByZeroException, FormatException, ApplicationException, OleDbException, etc.
Quando é lançada uma Exception?
Uma Exception é lançada sempre que ocorre um erro já definido (por exemplo, quando você tenta dividir um número inteiro por zero, chamando o DivideByZeroException). Caso você tenha criado uma Exception, informe quando ela será lançada, usando a palavra-chave throw. Veja na Listagem 1 como criar uma Exception e lançá-la no meio do código.
Listagem 1. Criação de uma Exception.
//código em C#
//Exception herdando de System.ApplicationException
using System
public class TextoInvalidoException : ApplicationException {
//algum código a ser modificado da Exception
}
// classe exemplo para lançar a Exception
public class App {
public void RecebeTexto(string texto) {
//Testa se o texto é vazio e lança a Exception
if (texto == “”) throw new TextoInvalidoException();
}
}
‘Código em Visual Basic .NET
‘Exception herdando de System.ApplicationException
Public Class TextoInvalidoException Inherits System.ApplicationException
‘algum código a ser modificado da Exception
End Class
‘classe exemplo para lançar a Exception
Public Class App
Public Sub RecebeTexto(texto As String)
‘Testa se o texto é vazio e lança a Exception
If texto = “” Then
Throw New TextoInvalidoException()
End If
End Sub
End Class
Como tratar os erros?
Além de lançar os erros, é necessário tratá-los. Para isso, você deve usar o bloco try, catch, finally. O bloco try contém os códigos a serem testados e executados. Caso ocorra algum erro, o bloco catch será executado. O bloco catch tem uma estrutura parecida com o switch do C# e o Case do VB. Assim, podemos executar códigos diferentes dependendo da Exception gerada. Como nem sempre sabemos qual Exception pode ser lançada pelo código, podemos ter um bloco catch genérico que é chamado quando uma Exception é lançada. Normalmente, colocamos esse catch genérico no final do bloco para garantirmos que ele só será executado se nenhuma outra Exception do bloco for lançada. Essa hierarquia é fundamental para personalizar o erro.
O bloco finally é opcional e geralmente é usado para limpar recursos, fechar conexão com banco de dados, fechar arquivos, etc. O código do bloco finally é sempre executado, independentemente de ter ocorrido ou não um erro no bloco try.
É importante lembrar que, se você criar uma variável em algum dos blocos, ela só estará acessível neste bloco, ou seja, ela não poderá ser acessada no bloco finally se tiver sido criada no bloco try. Veja um exemplo na Listagem 2.
Listagem 2. Uso do bloco try, catch , finally em C# e VB .NET.
//código em C#
public void MetodoAuxiliar() {
try
{
//código a ser testado
string texto = Console.ReadLine();
RecebeTexto(texto);
}
catch(TextoInvalidoException tie)
{ //será executado se ocorrer TextoInvalidoException
Console.WriteLine(“Você digitou uma string vazia!”);
}
catch(Exception ex)
{ //catch genérico pois é ativado por qualquer Exception
Console.WriteLine(“Ocorreu um erro!”);
}
Finally
{
//esse código é sempre executado
Console.WriteLine(“Sempre é executado!”);
}
}
‘Código em Visual Basic .NET
Public Sub MetodoAuxiliar
Try
‘código a ser testado
Dim texto As String = Console.ReadLine()
RecebeTexto(texto)
Catch tie As TextoInvalidoException
‘será executado se ocorrer TextoInvalidoException
Console.WriteLine(“Você digitou uma string vazia!”)
Catch ex As Exception
‘catch genérico pois é ativado por qualquer Exception
Console.WriteLine(“Ocorreu um erro!”)
Finally
‘esse código é sempre executado
Console.WriteLine(“Sempre é executado!”)
End Try
End Sub
Veja um exemplo de código de tratamento de erros que lê os dados de uma tabela, preenche um objeto SqlDataReader e o mostra na tela. Note que as variáveis são criadas fora dos blocos, de modo que possam ser acessadas em qualquer parte dos blocos try, catch ou finally. Cabe ressaltar que o bloco finally é usado para fechar a conexão e o SqlDataReader (processos freqüentemente executados). Veja um exemplo na Listagem 3.
Listagem 3. Uso do bloco try, catch , finally em Banco de Dados.
//Código em C# - método que lê dados e mostra
//na tela através de um SqlDataReader
public void LerDados() {
//cria as variáveis fora dos blocos
SqlConnection conexao;
SqlDataReader dr;
try
{
conexao = new SqlConnection(“Data Source=(local);Initial Catalog=Northwind;User Id=sa;Password=senha”);
//cria o objeto comando
SqlCommand comando = conexao.CreateCommand();
//define a string SQL do comando
comando.CommandText = “Select * from Products”;
//abre a conexão com o Banco
conexao.Open();
//preenche o SqlDataReader
dr = comando.ExecuteReader();
//lê dados do DataReader e mostra na tela
while(dr.Read())
{
Console.WriteLine(dr[0].ToString());
}
}
catch(SqlException sqlEx)
{
Console.WriteLine(“Erro no banco de dados”);
}
catch(Exception ex)
{
//código executado caso qualquer outra
//exceção além de SqlException seja lançada
Console.WriteLine(“Erro genérico”);
}
finally
{
//fecha a conexão e o DataReader
dr.Close();
conexao.Close();
}
}
‘código em VB.NET - método que lê dados e mostra
‘tela através de um SqlDataReader
Public Sub LerDados()
‘cria as variáveis fora dos blocos
Dim conexao As SqlConnection
Dim dr As SqlDataReader
Try
conexao = New SqlConnection(“Data Source=(local);Initial Catalog=Northwind;User Id=as;Password=senha”)
Dim commando As SqlCommand = conexao.CreateCommand() ‘criando o objeto comando
comando.CommandText = “Select * from Products”
‘define a string SQL do comando
conexao.Open() ‘abrindo a conexão com o Banco
‘preenche o SqlDataReader
dr = comando.ExecuteReader()
‘lê dados do DataReader e mostra na tela
While dr.Read
Console.WriteLine(dr(0).ToString())
End While
Catch sqlEx As SqlException
Console.WriteLine(“Erro no banco de dados”)
Catch ex As Exception
‘código executado caso qualquer outra
‘exceção além de SqlException seja lançada
Console.WriteLine(“Erro genérico”)
Finally
‘fecha a conexão e o DataReader
dr.Close()
conexao.Close()
End Try
End Sub
Conclusão
Vimos que a plataforma .NET nos oferece uma maneira mais estruturada de gerenciar erros com Exceptions. O fato de podermos criar erros customizados de acordo com a necessidade e de gerenciá-los com um código mais limpo usando o bloco “try, catch, finally” torna as Exceptions a melhor escolha.