VB.NET - Programando defensivamente


Errar é humano.

Errar programando é mais humano ainda.

Como temos quase certeza de erros serão cometidos durante o desenvolvimento temos que rastreá-los e remove-los, quando possível.

Acontece que nem todo erro pode ser rastreado ou removido do seu programa. Existem casos nos quais os erros podem acontecer sem que você seja o culpado.

Uma das operações mais básicas e comun, é acessar um arquivo em disco. Parece uma tarefa simples , pois ao acessar um arquivo você supõe que ele esta disponível para você; que ele esta onde você o deixou ; que ele não esta corrompido nem contaminado por um vírus ; mas você já deve estar cansado de saber que as coisas não são tão simples assim, e, que o arquivo pode ter sido movido, apagado, corrompido, contaminado, danificado; e isto vai gerar um erro no seu programa.

Portanto, em uma tarefa simples como a descrita acima você deve adotar procedimentos básicos de verificação para contornar as possíveis causas dos possíveis erros. Você pode então fazer uma lista de tudo o que achar que deve verificar e mesmo assim pode não conseguir prever todos os erros possíveis. Na verdade você não pode se defender contra todos os possíveis erros que possam ocorrer.

È justamente por isto que o Visual Basic .NET lhe oferece o gerenciamento estruturado de exceção - GEE. Vejamos o código para realizar a tarefa descrita acima usando o GEE.

        Dim arquivo As String
        Dim arquivoStream As System.IO.StreamReader

        Try
            'tenta acessar e ler o arquivo teste.txt
            arquivoStream = System.IO.File.OpenText("teste.txt")
            arquivo = arquivoStream.ReadLine
        Catch ex As Exception
            'se ocorrer uma exceção exibe a mensagem
            MessageBox.Show(ex.Message)
        Finally
            'se o arquivo existe então fecha o arquivo
            If Not arquivoStream Is Nothing Then
                arquivoStream.Close()
            End If
        End Try
A estrutura do GEE - Try/Catch/Finally

- A parte do código depois da declaração Try é o código que esta sendo tratado quanto a erros

- Sé ocorrer um erro a parte Catch do código será executada.

- A parte Finally SEMPRE será executada ocorra erro ou não.
Nesta parte do código podemos realizar operações que devem ser executadas de qualquer maneira como fechar conexões , arquivos , efetuar limpeza de ambiente , variáveis,...

 

Nota:  Para saber mais leia os artigos :

A base do GEE é o bloco Try/Catch/Finally - Tentar/Pegar/Finalizar ele substitui as declarações On Error Goto. Portanto se você pretende usar o VB.NET como linguagem de desenvolvimento use o GEE e não mais a estrutura  On Error Goto pois ela esta disponível por questão de compatibilidade.(Não existe nada mais feio que um código VB.NET usando On error Goto...)

O GEE trouxe um novo jargão com o qual você deve se habituar. Não existe mais um erro (que bom...) mas uma exceção ; as exceções são lançadas por código mal comportado e o bloco Try/Catch pega a exceção emitida para tratamento.

Funcionamento básico do GEE :

Quando um erro ocorre no seu programa o VB.NET tenta encontrar uma declaração Catch no procedimento atual; se não encontrar nenhuma ele continua buscando através de declarações Catch no que código que chamou o procedimento atual. Esse processo continua por toda a pilha (stack) até que seja encontrado um bloco Catch que possa tratar o erro atual ou até que o recurso de busca atinja o nível mais externo superior do aplicativo. Neste ponto um erro em tempo de execução será gerado e o programa será encerrado.

O Objeto Exception

O objeto exception é base do GEE. O objeto exception básico é o System.Exception (foi usado no exemplo acima).

Este objeto também existe em muitas versões diferentes e mais especializadas que herdam de System.Exception.

No exemplo anterior a exceção que ocorreu poderia ter System.IO.FileNotFoundException se o arquivo não existisse ou System.IO.EndOfStreamException se o arquivo existisse mas não tivesse conteúdo.

Vamos examinar o objeto Exception de perto usando o código acima. Crie um projeto do tipo Windows Application no VS.NET usando a linguagem VB.NET e no evento Load do formulário copie o código acima. A seguir coloque um ponto de interrupção no bloco Catch. Veja abaixo como deverá ficar o código :

Quando você executar o programa deve ocorrer uma exceção, pois o arquivo teste.txt não deve existir na pasta local do aplicativo. É exatamente isto que queremos que ocorra. Quando chegar no ponto de interrupção ative a janela Locals.Vamos então espiar de perto a estrutura de objeto da exceção que pegou usando a Janela Locals.

Abaixo temos a exibição da janela Locals. Estamos interessados nos dados públicos do objeto Exception.

O objeto ex é um objeto do tipo Exception que usamos no código para tratamento das exceções é ele que devemos espiar.

Vejamos o que informações podemos extrair do objeto ex:

MessageBox.Show(ex.Message & vbCrLf & vbCrLf & ex.StackTrace)

Ao executar o programa teremos a seguinte mensagem:

Uma propriedade muito interessante é a propriedade InnerException (exceção interna) que embora não apareça no exemplo acima pode ser usada quando ocorre mais de um erro em uma sucessão rápida. O VB.NET permite empacotar um erro anterior na propriedade InnerException.

Neste nosso exemplo usamos uma rotina genérica de gerenciamento de erro que tratava com qualquer erro que ocorresse. Podemos no entanto identificar tipos específicos de exceções e tratá-las de separadamente. Para fazer isto devemos definir diversas declarações Catch , cada uma destinada a tratar com o tipo de exceção.

Vejamos como podemos fazer isto para o nosso exemplo:

      Try
            'tenta acessar e ler o arquivo teste.txt
            arquivoStream = System.IO.File.OpenText("teste.txt")
            arquivo = arquivoStream.ReadLine
        Catch ex As System.IO.FileNotFoundException
            'se o arquivo não for encontrado exibe a mensagem
            MessageBox.Show("Arquivo não localizado" & vbCrLf & vbCrLf & ex.StackTrace)
        Catch ex As System.IO.EndOfStreamException
            'se o conteudo do arquivo for inválido exibe a mensagem
            MessageBox.Show("Conteúdo do arquivo inválido." & vbCrLf & vbCrLf & ex.StackTrace)
        Catch ex As Exception
            'se ocorrer qualquer outra exceção exibe a mensagem
            MessageBox.Show(ex.Message & vbCrLf & vbCrLf & ex.StackTrace)
        Finally
            'se o arquivo existe então fecha o arquivo
            If Not arquivoStream Is Nothing Then
                arquivoStream.Close()
            End If
        End Try

 

Então ao escrever o seu código será muito útil você saber quais tipos de exceção pode esperar para assim poder tratá-las de uma forma mais adequada. Você pode ver todas as exceções para um determinado manespace selecionando no Debug a opção Exceptions(CTRL_ALT+E). A janela Exceptions mostra todas as exceções na biblioteca de classe .NET organizadas.

Esta janela pode ser usada como uma ferramenta de depuração muito útil. Podemos usar as opções oferecidas para ajustar individualmente opções de execução para cada tipo de exceção.

Filtragem por condições

Você pode usar o recurso de filtrar o seu código com base em qualquer expressão condicional usando a palavra-chave When. A utilização desta cláusula será útil quando o objeto Exception contiver múltiplos erros. Abaixo um exemplo da utilização da cláusula When.

Dim i As Integer = 10
Dim j As Integer = 0
Dim k As Integer 
Try
    k = i \ j
Catch exc As Exception When j=0
  Console.WriteLine("Não existe divisão por zero")
Catch exc As Exception
  Console.WriteLine("Ocorreu um erro na operação")
Finally
  Beep
  Console.ReadLine()
End Try

 

Um outro exemplo poderia ser feito usando o código a seguir:

Do
Dim tentativa As Integer
Try
   ' aqui vai o código que terá o tratamento de erros
Catch ex As IO.FileLoadException When tentativa < 3
    ' Ao ocorrer a exceção pergunta se quer tentar novamente até o limite de 3 tentativas
    If MsgBox("Quer tentar novamente ?", MsgBoxStyle.YesNo) = MsgBoxResult.No Then
        Exit Do
     End If
Catch ex As Exception
    ' Se ocorrer qualquer outro erro ou o número de tentivas for maior que 3
     MsgBox(ex.Message)
     Exit Do
End Try
' incrementa a tentativa
tentativa += 1
Loop

Usando asserções

O VB.NET possui um recurso chamado asserções que força o seu código a testar certas suposições que você crê que estejam ocorrendo para que erros potenciais sejam minimizados.

Asserções são declarações que você garante que são verdadeiras, pois de outro modo há algo errado com o código do seu aplicativo. Ao testar uma asserção e descobrir que ela é falsa , o VB.NET enviará uma mensagem de erro com uma pilha de código de diagnóstico e lhe dará a opção de interromper a execução ou de ignorar o problema e prosseguir.

As asserções só funcionam em modo de depuração e quando você compila e distribui o seu programa todas as asserções desaparecem. Com isto as asserções tem o nítido objetivo de ajudá-lo a localizar problemas durante o teste do seu aplicativo.

Para incluir uma asserção em seu código , use o método Assert a classe Debug.

Vamos supor que você deve informar o caminho e nome de um arquivo a ser acessado em uma caixa de texto. Podemos usar asserções conforme o código a seguir :

 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim arquivo As String
        Dim arquivoStream As System.IO.StreamReader
        Debug.Assert(TextBox1.Text = "")
        Try
            arquivoStream = System.IO.File.OpenText(TextBox1.Text)
            arquivo = arquivoStream.ReadLine
        Catch ex As System.IO.FileNotFoundException
            MessageBox.Show("Arquivo não localizado" & vbCrLf & vbCrLf & ex.StackTrace)
        Catch ex As System.IO.EndOfStreamException
            MessageBox.Show("Conteúdo do arquivo inválido." & vbCrLf & vbCrLf & ex.StackTrace)
        Catch ex As Exception
            MessageBox.Show(ex.Message & vbCrLf & vbCrLf & ex.StackTrace)
        Finally
            If Not arquivoStream Is Nothing Then
                arquivoStream.Close()
            End If
        End Try
    End Sub

 

Se o nome do arquivo informado estiver vazio iremos obter a mensagem abaixo:

Como as asserções depuradas são completamente removidas da versão final do seu programa não se preocupe que elas não vão tornar o seu programa mais lento. Tome cuidado , no entanto , em não permitir que uma asserção chame um procedimento que modifique um valor de alguma variável do seu programa , pois ai sim você terá grandes dores de cabeça com o seu código.

Além disto você pode usar também o rastreio de asserções. Neste caso o rastreio permanece no programa final . Geralmente você não irá precisar fazer isto em seu programa local mas pode usar o rastreio em um programa remoto. Exemplo de rastreio de asserção:

Trace.Assert(TextBox1.Text = "")

Como você pode usar estes conceitos na prática ?

Muitas vezes o cliente ou usuário do seu programa não sabe explicar como ou quando um determinado erro foi gerado em sua aplicação.

Você pode criar um arquivo de registro no seu aplicativo de forma que ele capture informações de sequência de execução do seu programa e grave em um arquivo . Quando ocorrer algum problema com seu aplicativo você somente terá que solicitar ao seu cliente que envie o arquivo de registro para analisar o trace gerado pela aplicação e descobrir o que causou o erro.

Para usar o rastreio você usa a classe Trace do namespace System.Diagnostics e para capturar as informações para um arquivo você usa um listener que será um arquivo texto que ficará recebendo todas as saídas do rastreio. Vejamos o exemplo abaixo :

Primeiro devemos criar o arquivo que será usado como registro do Trace. Abaixo criamos o Listener chamado log.txt

      Dim arqTrace As New TextWriterTraceListener(File.Create("log.txt"))
        Trace.AutoFlush() = True
        Trace.Listeners.Add(arqTrace)

Agora podemos usar os métodos da classe Trace para escrever o arquivo texto. Vamos escrever o trace na código exemplo que acessa um arquivo :

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim arquivo As String
        Dim arquivoStream As System.IO.StreamReader

        Trace.WriteLine("Iniciando aplicação")
        Trace.Indent()
        Trace.WriteLine("Acessando o arquivo " & TextBox1.Text)

        Try
            arquivoStream = System.IO.File.OpenText(TextBox1.Text)
            arquivo = arquivoStream.ReadLine
        Catch ex As System.IO.FileNotFoundException
            Trace.WriteLine("Erro ao acessando o arquivo " & TextBox1.Text)
            MessageBox.Show("Arquivo não localizado" & vbCrLf & vbCrLf & ex.StackTrace)
        Catch ex As System.IO.EndOfStreamException
            MessageBox.Show("Conteúdo do arquivo inválido." & vbCrLf & vbCrLf & ex.StackTrace)
        Catch ex As Exception
            MessageBox.Show(ex.Message & vbCrLf & vbCrLf & ex.StackTrace)
        Finally
            Trace.WriteLine("Encerrando aplicação. Executando finally.")
            Trace.Unindent()
            Trace.Close()
            If Not arquivoStream Is Nothing Then
                arquivoStream.Close()
            End If
        End Try
    End Sub

 

O arquivo log.txt será gerado na pasta bin da aplicação e terá o seguinte conteúdo:

Iniciando aplicação
Acessando o arquivo
    Encerrando aplicação. Executando finally.

Com isto você pode gerar um arquivo de log de monitoração para a sua aplicação.

Uma outra forma de monitorar a sua aplicação e usar o método Writeline da classe Debug para imprimir informações de diagnóstico na janela OutPut. Exemplo:

Debug.Writeline(" informação de diagnostico...")

Mas atenção , para que garantir que o rastreio da sua aplicação esteja ativo faça o seguinte :

Com os conceitos tratados neste artigos , mesmo que o seu código não fique totalmente livre de erros , com certeza ele será mais robusto e mais confiável. E quando os problemas surgirem você estará capacitado a resolvê-los com mais rapidez.

Ate o próximo artigo VB.NET ...

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti