VB .NET - Estratégia para Tratamento de exceções
Qual a melhor estratégia para efetuar o tratamento de exceções em uma aplicação ? Quais exceções devo utilizar ? Como efetuar um tratamento de exceções eficiente ? |
Se você ainda tem estas dúvidas este artigo se propõe a mostrar como você pode montar uma estratégia de tratamento de exceções para aplicações VB.NET. Antes de prosseguir sugiro que você leia os artigos já publicados no site, se o assunto for novo para você.
Recordando rapidamente alguns conceitos básicos
O tratamento de exceções é implementado usando a estrutura de comandos : Try.. Catch...Finally..End Try cuja sintaxe básica é a seguinte:
Try |
' código que pode gerar/disparar uma exceção |
Catch |
' código que efetua o tratamento da exceção |
Finally |
' efetua a limpeza do código (fechamento de conexões, destruição de objetos usados , etc...) |
End Try |
As instruções Try/End Try são obrigatórias. As cláusulas Catch/Finally podem ser usadas no interior do bloco Try/End Try, mas pelo menos uma delas é de uso obrigatório. Você pode ter mais de um Catch no interior do bloco.
Você pode usar as exceções padrão que a plataforma .NET contém; todas elas derivam da classe base System.Exception. As exceções mais comuns estão listadas abaixo:
Você não esta limitado a usar somente as exceções que a .NET Framework oferece pode também criar e lançar as suas próprias exceções. Para disparar uma exceção você usa a cláusula Throw :
Throw new ArgumentOutOfRangeException
onde :
ArgumentOutOfRangeException - informa o tipo de exceção que esta sendo lançada.
Nesta altura eu já posso lançar a questão :
"Qual a melhor maneira de usar e tratar exceções em uma aplicação VB.NET ?"
Creio que você já está consciente que deve procurar capturar diferentes tipos de exceções e saber o que fazer com cada uma delas em uma aplicação VB.NET. Existirão momentos que você deverá lançar uma exceção avisando o usuário de forma amigável para o problema que esta ocorrendo em outras ocasiões você deverá efetuar um tratamento mas elaborado.
De forma geral existem três formas de abordar o problema de tratamento de exceções :
Você captura todas as exceções
Você passa adiante todas as exceções
Você cria sua própria exceção customizada e mapeia todas as exceções para esta classe.
A melhor forma de tratar o problema é a terceira opção onde você cria uma classe de exceção customizada. Quando você cria um tipo de exceção customizada você ganha controle em todas as propriedades da exceção e pode também incluir propriedades a sua classe customizada.
Nota: A linguagem Java todos os métodos usam a instrução throw para lançar uma exceção. A instrução throw requer um argumento simples: um objeto que seja passível de ser lançado. Em Java objetos passíveis de serem lançados são instâncias de qualquer sub-classe da classe Throwable. Se você tentar lançar um objeto que não seja passível de ser lançado o compilador vai recusar na compilação do programa e indicar um erro. A cláusula throws especifica quais exceções o método pode lançar. Você usa a instrução throws na assinatura do método informando quais exceções está lançando. Na plataforma .NET não existe a cláusula throws na assinatura de métodos. Desta forma , você deve documentar explicitamente as exceções que esta lançando para que o usuário saiba. Parece que isto foi feito intencionalmente de forma a que se tenha um tratamento de erros centralizado. A plataforma .NET também não possui as Checked Excpetions que a linguagem Java Possui. |
Vejamos um exemplo básico para que você entenda melhor:
Imagine o seguinte trecho de código :
Function getCliente()
As
Boolean
Try Dim pessoa As String = Cliente.buscaCliente("Macoratti") Catch sqle As SqlException Throw New ClienteException("Não foi possível localizar o cliente", sqle) End Try End Function |
Esta função realiza uma busca pelo cliente Macoratti e lança uma exceção do tipo ClienteException se houver um erro do tipo SqlException.
Percebeu que a exceção ClienteException não é uma exceção padrão do .NET Framework. De onde terá ela surgido ?
A resposta é : a exceção ClienteException é uma exceção personalizada que foi criada pelo usuário e que possui o seguinte código:
Public Class ClienteException
Inherits Exception Private minhaException_ As Exception
Public Sub New(ByVal mensagem As String, ByVal excMac As Exception) MyBase.New(mensagem, excMac) minhaException_ = excMac
End
Sub Return (minhaException_) End Function End Class |
A classe de exceção customizada - ClienteException - entende a exceção real lançada como um argumento e transforma a mensagem de nível de sistema em outra mensagem para o nível da aplicação. Além disto você tem a exceção original que casou o erro como parte da nova instância do objeto exceção.(minhaException_)
A classe ClienteException usa dois argumentos : a mensagem (mensagem) que podemos exibir e a exceção real (excMac) que causou a exceção. Assim, para saber a real causa da exceção que disparou ClienteException, basta chamar o método getMinhaException().
Aplicando a estratégia
Vamos agora mostrar que a teoria funciona na prática. Vamos aplicar o conceito a uma pequena aplicação feita no VB2005 que faz acesso a um banco de dados Access - clientes.mdb.
1- Crie um novo projeto no Visual Basic 2005 e inclua uma nova classe chamada DataBaseException.vb com o seguinte código:
Public Class DataBaseExceptionInherits Exception
End Sub Public Sub New(ByVal message As String) MyBase.New(message) End Sub Public Sub New(ByVal mensagem As String, ByVal inner As Exception) MyBase.New(mensagem, inner) End Sub
|
2- No formulário padrão form1.vb inclua os seguintes controles : Label, TextBox(txtCodigoCliente), Button(btnExibirDados) e ListView(lstaClientes) , conforme figura abaixo:
Agora vamos definir duas classes para tratar as seguintes exceções :
CustomerNotFoundException - lançada quando um cliente não for localizado na base de dados
DataBaseUnavaillableException - lançada quando o banco de dados não pode ser acessado
Inclua um novo módulo de classe de nome CustomerNotFoundException.vb com o seguinte código :
Public Class CustomerNotFoundExceptionInherits DataBaseException
Private codigoCliente_ As Long Public ReadOnly Property CodigoCliente() As Long Get Return CodigoClienteEnd Get End PropertyPublic Sub New(ByVal codigoCliente As Long) MyBase.New("Código do cliente não localizado.") codigoCliente_ = codigoCliente
End
Sub End Class |
Agora Inclua um novo módulo de classe de nome DataBaseUnavaillableException.vb com o seguinte código :
Public Class
DatabaseUnavailableException Inherits DataBaseException Public
Sub
New(ByVal
ex As System.Exception) End Class |
Perceba que ambas as classes herdam da nossa classe customizada DataBaseException.vb que por sua vez herda de Exception.
Vamos criar também uma classe chamada Cliente cujo objetivo será acessar a base de dados e selecionar os dados dos clientes. Para isto inclua um novo módulo de classe chamado Cliente.vb e insira o seguinte código: :
Imports System.Data.oledb
Private Shared telefone_ As String
ConectaBD(database, cn) GetDadosCliente(cn, CodigoCliente) DesconectaBD(cn) End Sub Private Sub ConectaBD(ByVal database As String, ByRef cn As OleDbConnection)
cn.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
"""" & database
& """" cn.Open() Catch ex As Exception Throw New DatabaseUnavailableException(ex)
End
Try Private Sub DesconectaBD(ByRef cn As OleDbConnection) cn.Close() cn.Dispose() End Sub Private Sub GetDadosCliente(ByVal cn As OleDbConnection, ByVal codigoCliente As Long)
Dim cmd As New OleDbCommand Dim reader As OleDbDataReader
cmd.Connection = cn cmd.CommandText = "SELECT * FROM tblClientes WHERE codigo = " & codigoCliente reader = cmd.ExecuteReader
If reader.HasRows Then reader.Read() Codigo_ = reader.Item("Codigo") Nome_ = reader.Item("Nome") Endereco_ = reader.Item("Endereco") telefone_ = reader.Item("Telefone") Else Throw New CustomerNotFoundException(codigoCliente) End If End Sub
ReadOnly Property codigo() Get Return Codigo_End Get End PropertyReadOnly Property nome() Get Return Nome_ End Get End PropertyReadOnly Property endereco() Get Return Endereco_End Get End PropertyReadOnly Property telefone() Get Return telefone_End Get End Property
|
Podemos usar o mesmo tratamento de exceção para conexão como SQL Server (no meu caso o SQL Server Express 2005). Estarei fazendo o acesso a tabela tblClientes do banco de dados Cadastro.mdf que foi criado clicando com o botão direito do mouse sobre o nome do projeto e a seguir selecionando Add -> New Item , selecionando em seguida a opção SQL DataBase com o nome de Cadastro.mdf.
Vamos criar um novo formulário - form2.vb - e incluir os seguintes controles neste formulário : Button (btnExibirDados) e DataGridView (dgv1), conforme figura abaixo:
Agora no evento Click do botão - Exibir Dados
Private
Sub
btnExibirDados_Click(ByVal
sender As System.Object,
ByVal e
As System.EventArgs)
Handles
btnExibirDados.Click
Dim connection
As SqlConnection = New
SqlConnection("Data
da.TableMappings.Add("Table", "tblClientes")
cmd.CommandType = System.Data.CommandType.Text da.SelectCommand = cmd Dim ds As DataSet = New DataSet("Clientes") da.Fill(ds) dgv1.DataSource = ds.Tables(0) Catch exception As SqlException Throw New DataBaseException(exception.Message, exception) Finally If Not connection Is Nothing Then connection.Dispose() End If End Try End Sub |
Nota: A string de conexão com o SQL Server 2005 foi obtida através do assistente de criação de Data Source.
Se testarmos os projetos criados veremos que as classes criadas para tratar as exceções funcionam perfeitamente. Fica a seu cargo melhorá-las.
Aguardo você no próximo artigo VB.NET...
Referências: