Try...Catch...Finally Instrução (Visual Basic)

Oferece uma forma de lidar com alguns ou com todos os possíveis erros que podem ocorrer em um determinado bloco de código e, ainda assim, executar o código.

Sintaxe

Try
    [ tryStatements ]
    [ Exit Try ]
[ Catch [ exception [ As type ] ] [ When expression ]
    [ catchStatements ]
    [ Exit Try ] ]
[ Catch ... ]
[ Finally
    [ finallyStatements ] ]
End Try

Partes

Termo Definição
tryStatements Opcional. Instruções em que um erro pode ocorrer. Pode ser uma instrução composta.
Catch Opcional. Vários blocos Catch permitidos. Se ocorrer uma exceção ao processar o bloco Try, cada instrução Catch será examinada em ordem textual para determinar se ela manipula a exceção, sendo que exception representa a exceção que foi gerada.
exception Opcional. Qualquer nome de variável. O valor inicial de exception é o valor do erro gerado. Usado com Catch para especificar o erro capturado. Se omitida, a instrução Catch captura qualquer exceção.
type Opcional. Especifica o tipo de filtro de classe. Se o valor de exception for do tipo especificado por type ou de um tipo derivado, o identificador ficará associado ao objeto de exceção.
When Opcional. Uma instrução Catch com uma cláusula When captura exceções somente quando expression é avaliada como True. Uma cláusula When é aplicada somente depois de verificar o tipo da exceção e expression pode se referir ao identificador que representa a exceção.
expression Opcional. Deve ser implicitamente conversível para Boolean. Qualquer expressão que descreva um filtro genérico. Normalmente usado para filtrar por número de erro. Usado com a palavra-chave When para especificar as circunstâncias sob as quais o erro é capturado.
catchStatements Opcional. Instruções para lidar com erros que ocorrem no bloco Try associado. Pode ser uma instrução composta.
Exit Try Opcional. Palavra-chave que sai da estrutura Try...Catch...Finally. A execução é retomada com o código imediatamente após a instrução End Try. A instrução Finally ainda será executada. Não permitido em blocos Finally.
Finally Opcional. Um bloco Finally sempre é executado quando a execução deixa qualquer parte da instrução Try...Catch.
finallyStatements Opcional. Instruções executadas após a conclusão de todos os outros processamentos de erros.
End Try Termina a estrutura Try...Catch...Finally.

Comentários

Se você espera que uma exceção específica possa ocorrer durante uma determinada seção de código, coloque o código em um bloco Try e use um bloco Catch para manter o controle e manipular a exceção se ocorrer.

A instrução Try…Catch consiste em um bloco Try seguido por uma ou mais cláusulas Catch, que especificam os manipuladores para diferentes exceções. Quando uma exceção é lançada em um bloco Try, o Visual Basic procura a instrução Catch que manipula a exceção. Se uma instrução Catch correspondente não for encontrada, o Visual Basic examinará o método que chamou o método atual e assim por diante na pilha de chamadas. Se nenhum bloco Catch for encontrado, o Visual Basic exibirá uma mensagem de exceção sem tratamento para o usuário e interromperá a execução do programa.

Você pode usar mais de uma instrução Catch em uma instrução Try…Catch. Se você fizer isso, a ordem das cláusulas Catch será significativa porque elas são examinadas em ordem. Catch as exceções mais específicas antes das menos específicas.

As condições de instrução a seguir Catch são as menos específicas e serão catch todas as exceções derivadas da classe Exception. Normalmente, você deve usar uma dessas variações como o último bloco Catch da estrutura Try...Catch...Finally, depois de capturar todas as exceções específicas esperadas. O fluxo de controle nunca pode alcançar um bloco Catch que siga qualquer uma dessas variações.

  • O type é Exception, por exemplo: Catch ex As Exception

  • A instrução não tem nenhuma variável exception, por exemplo: Catch

Quando uma instrução Try…Catch…Finally é aninhada em outro bloco Try, o Visual Basic examina primeiro cada instrução Catch no bloco Try mais interno. Se nenhuma instrução Catch correspondente for encontrada, a pesquisa prosseguirá para as instruções Catch do bloco Try…Catch…Finally externo.

As variáveis locais de um bloco Try não estão disponíveis em um bloco Catch porque são blocos separados. Se você quiser usar uma variável em mais de um bloco, declare a variável fora da estrutura Try...Catch...Finally.

Dica

A instrução Try…Catch…Finally está disponível como um snippet de código do IntelliSense. No Gerente de Snippets de Código, expanda Padrões de Código – If, For Each,TryCatch, Property etc. e Tratamento de Erros (Exceções). Para obter mais informações, consulte Snippets de Código.

Bloco Finally

Se você tiver uma ou mais instruções que precisam ser executadas antes que você saia da estado Try, use um bloco Finally. O controle passa para o bloco Finally pouco antes de ele sair da estrutura Try…Catch. Isso é verdadeiro mesmo se ocorrer uma exceção em qualquer lugar dentro da estrutura Try.

Um bloco Finally é útil para executar qualquer código que precise ser executado mesmo se houver uma exceção. O controle é passado para o bloco Finally, independentemente de como o bloco Try...Catch sai.

O código em um bloco Finally é executado mesmo que seu código encontre uma instrução Return em um bloco Try ou Catch. O controle não passa de um bloco Try ou Catch para o bloco Finally correspondente nos seguintes casos:

Não é válido transferir explicitamente a execução para um bloco Finally. A transferência da execução de um bloco Finally não é válida, exceto por meio de uma exceção.

Se uma instrução Try não contiver pelo menos um bloco Catch, ela deverá conter um bloco Finally.

Dica

Se você não tiver exceções catch específicas, a instrução Using se comportará como um bloco Try…Finally e garantirá o descarte dos recursos, independentemente de como você sai do bloco. Isso é verdadeiro mesmo com uma exceção sem tratamento. Para obter mais informações, consulte Instrução using.

Argumento de exceção

O argumento exception do bloco Catch é uma instância da classe Exception ou uma classe que deriva da classe Exception. A instância da classe Exception corresponde ao erro que ocorreu no bloco Try.

As propriedades do objeto Exception ajudam a identificar a causa e o local de uma exceção. Por exemplo, a propriedade StackTrace lista os métodos chamados que levaram à exceção, ajudando você a encontrar onde o erro ocorreu no código. Message retorna uma mensagem que descreve a exceção. HelpLink retorna um link para um arquivo de Ajuda associado. InnerException retorna o objeto Exception que causou a exceção atual ou retorna Nothing se não houver nenhum Exception original.

Considerações ao usar uma instrução Try…Catch

Use uma instrução Try…Catch apenas para sinalizar a ocorrência de eventos de programa incomuns ou inesperados. Os motivos para isso incluem o seguinte:

  • Capturar exceções em tempo de execução cria sobrecarga adicional e provavelmente será mais lento do que a pré-verificação para evitar exceções.

  • Se um bloco Catch não for tratado corretamente, a exceção poderá não ser relatada corretamente aos usuários.

  • O tratamento de exceções torna um programa mais complexo.

Nem sempre você precisa de uma instrução Try…Catch para verificar se há uma condição que provavelmente ocorrerá. O exemplo a seguir verifica se um arquivo existe antes de tentar abri-lo. Isso reduz a necessidade de capturar uma exceção gerada pelo método OpenText.

Private Sub TextFileExample(ByVal filePath As String)

    ' Verify that the file exists.
    If System.IO.File.Exists(filePath) = False Then
        Console.Write("File Not Found: " & filePath)
    Else
        ' Open the text file and display its contents.
        Dim sr As System.IO.StreamReader =
            System.IO.File.OpenText(filePath)

        Console.Write(sr.ReadToEnd)

        sr.Close()
    End If
End Sub

Verifique se o código em blocos Catch pode relatar corretamente exceções aos usuários, seja por meio do registro em log thread-safe ou de mensagens apropriadas. Caso contrário, as exceções podem permanecer desconhecidas.

Métodos assíncronos

Se marcar um método com o modificador Async, você poderá usar o operador Await no método. Uma instrução com o operador Await suspende a execução do método até que a tarefa aguardada seja concluída. A tarefa representa um trabalho em andamento. Quando a tarefa que está associada ao operador Await for concluída, a execução será retomada no mesmo método. Para obter mais informações, confira Fluxo de controle em programas assíncronos.

Uma tarefa retornada por um método Async pode terminar em um estado com falha, indicando que ela foi concluída devido a uma exceção sem tratamento. Uma tarefa também pode terminar em um estado cancelado, o que resulta na expulsão de OperationCanceledException da expressão await. Para catch qualquer tipo de exceção, coloque a expressão Await associada à tarefa em um bloco Try e catch a exceção no bloco Catch. Um exemplo é fornecido posteriormente neste tópico.

Uma tarefa pode estar em um estado com falha porque várias exceções foram responsáveis pela falha. Por exemplo, a tarefa pode ser o resultado de uma chamada para Task.WhenAll. Quando você espera uma tarefa, a exceção capturada é somente uma das exceções e não é possível prever qual exceção será capturada. Um exemplo é fornecido posteriormente neste tópico.

Uma expressão Await não pode estar dentro de um bloco Catch ou Finally.

Iterators

Uma função iteradora ou um acessador Get realiza uma iteração personalizada em uma coleção. Um iterador usa uma instrução Yield para retornar um elemento da coleção por vez. Você chama uma função iteradora usando uma instrução For Each...Next.

Uma instrução Yield pode estar dentro de um bloco Try. Um bloco Try que contém uma instrução Yield pode ter blocos Catch e pode ter um bloco Finally. Para obter um exemplo, confira Try Blocos.

Uma instrução Yield não pode estar dentro de um bloco Catch ou bloco Finally.

Se o corpo For Each (fora da função iteradora) lançar uma exceção, um bloco Catch na função iteradora não será executado, mas um bloco Finally na função iteradora será executado. Um bloco Catch dentro de uma função iteradora captura apenas exceções que ocorrem dentro da função iteradora.

Situações de confiança parcial

Em situações de confiança parcial, como um aplicativo hospedado em um compartilhamento de rede, Try...Catch...Finally não catch há exceções de segurança que ocorrem antes que o método que contém a chamada seja invocado. O exemplo a seguir, ao colocá-lo em um compartilhamento de servidor e executar desse local, produz o erro "System.Security.SecurityException: Request Failed". Para obter mais informações sobre exceções de segurança, confira a classe SecurityException.

Try
    Process.Start("http://www.microsoft.com")
Catch ex As Exception
    Console.WriteLine("Can't load Web page" & vbCrLf & ex.Message)
End Try

Em uma situação de confiança parcial, você precisa colocar a instrução Process.Start em um Sub separado. A chamada inicial para o Sub falhará. Isso permite Try...Catch a catch antes de Sub que contém Process.Start seja iniciado e a exceção de segurança produzida.

Exemplos

A estrutura de Try...Catch...Finally

O exemplo a seguir ilustra a estrutura da instrução Try...Catch...Finally.

Public Sub TryExample()
    ' Declare variables.
    Dim x As Integer = 5
    Dim y As Integer = 0

    ' Set up structured error handling.
    Try
        ' Cause a "Divide by Zero" exception.
        x = x \ y

        ' This statement does not execute because program
        ' control passes to the Catch block when the
        ' exception occurs.
        Console.WriteLine("end of Try block")
    Catch ex As Exception
        ' Show the exception's message.
        Console.WriteLine(ex.Message)

        ' Show the stack trace, which is a list of methods
        ' that are currently executing.
        Console.WriteLine("Stack Trace: " & vbCrLf & ex.StackTrace)
    Finally
        ' This line executes whether or not the exception occurs.
        Console.WriteLine("in Finally block")
    End Try
End Sub

Exceção em um método chamado de um bloco de Try

No exemplo a seguir, o método CreateException gera um NullReferenceException. O código que gera a exceção não está em um bloco Try. Portanto, o método CreateException não manipula a exceção. O método RunSample manipula a exceção porque a chamada para o método CreateException está em um bloco Try.

O exemplo inclui instruções Catch para diversos tipos de exceções, ordenadas da mais específica para a mais geral.

Public Sub RunSample()
    Try
        CreateException()
    Catch ex As System.IO.IOException
        ' Code that reacts to IOException.
    Catch ex As NullReferenceException
        Console.WriteLine("NullReferenceException: " & ex.Message)
        Console.WriteLine("Stack Trace: " & vbCrLf & ex.StackTrace)
    Catch ex As Exception
        ' Code that reacts to any other exception.
    End Try
End Sub

Private Sub CreateException()
    ' This code throws a NullReferenceException.
    Dim obj = Nothing
    Dim prop = obj.Name

    ' This code also throws a NullReferenceException.
    'Throw New NullReferenceException("Something happened.")
End Sub

A instrução Catch When

O exemplo a seguir mostra como usar uma instrução Catch When para filtrar em uma expressão condicional. Se a expressão condicional for avaliada como True, o código no bloco Catch será executado.

Private Sub WhenExample()
    Dim i As Integer = 5

    Try
        Throw New ArgumentException()
    Catch e As OverflowException When i = 5
        Console.WriteLine("First handler")
    Catch e As ArgumentException When i = 4
        Console.WriteLine("Second handler")
    Catch When i = 5
        Console.WriteLine("Third handler")
    End Try
End Sub
' Output: Third handler

Instruções de Try aninhadas

O exemplo a seguir tem uma instrução Try…Catch contida em um bloco Try. O bloco Catch interno gera uma exceção que tem a propriedade InnerException definida como a exceção original. O bloco Catch externo relata a própria exceção e a exceção interna.

Private Sub InnerExceptionExample()
    Try
        Try
            ' Set a reference to a StringBuilder.
            ' The exception below does not occur if the commented
            ' out statement is used instead.
            Dim sb As System.Text.StringBuilder
            'Dim sb As New System.Text.StringBuilder

            ' Cause a NullReferenceException.
            sb.Append("text")
        Catch ex As Exception
            ' Throw a new exception that has the inner exception
            ' set to the original exception.
            Throw New ApplicationException("Something happened :(", ex)
        End Try
    Catch ex2 As Exception
        ' Show the exception.
        Console.WriteLine("Exception: " & ex2.Message)
        Console.WriteLine(ex2.StackTrace)

        ' Show the inner exception, if one is present.
        If ex2.InnerException IsNot Nothing Then
            Console.WriteLine("Inner Exception: " & ex2.InnerException.Message)
            Console.WriteLine(ex2.StackTrace)
        End If
    End Try
End Sub

Tratamento de exceções para métodos assíncronos

O exemplo a seguir ilustra o tratamento de exceção para métodos assíncronos. Para catch uma exceção que se aplica a uma tarefa assíncrona, a expressão Await está em um bloco Try do chamador e a exceção é capturada no bloco Catch.

Remova a marca de comentário da linha Throw New Exception no exemplo para demonstrar o tratamento de exceção. A exceção é capturada no bloco Catch, a propriedade IsFaulted da tarefa é definida como True e a propriedade Exception.InnerException da tarefa é definida como a exceção.

Remova a marca de comentário da linha Throw New OperationCancelledException para demonstrar o que acontece quando você cancela um processo assíncrono. A exceção é capturada no bloco Catch e a propriedade IsCanceled da tarefa é definida como True. No entanto, em algumas condições que não se aplicam a este exemplo, a propriedade IsFaulted é definida como True e IsCanceled é definido como False.

Public Async Function DoSomethingAsync() As Task
    Dim theTask As Task(Of String) = DelayAsync()

    Try
        Dim result As String = Await theTask
        Debug.WriteLine("Result: " & result)
    Catch ex As Exception
        Debug.WriteLine("Exception Message: " & ex.Message)
    End Try

    Debug.WriteLine("Task IsCanceled: " & theTask.IsCanceled)
    Debug.WriteLine("Task IsFaulted:  " & theTask.IsFaulted)
    If theTask.Exception IsNot Nothing Then
        Debug.WriteLine("Task Exception Message: " &
            theTask.Exception.Message)
        Debug.WriteLine("Task Inner Exception Message: " &
            theTask.Exception.InnerException.Message)
    End If
End Function

Private Async Function DelayAsync() As Task(Of String)
    Await Task.Delay(100)

    ' Uncomment each of the following lines to
    ' demonstrate exception handling.

    'Throw New OperationCanceledException("canceled")
    'Throw New Exception("Something happened.")
    Return "Done"
End Function


' Output when no exception is thrown in the awaited method:
'   Result: Done
'   Task IsCanceled: False
'   Task IsFaulted:  False

' Output when an Exception is thrown in the awaited method:
'   Exception Message: Something happened.
'   Task IsCanceled: False
'   Task IsFaulted:  True
'   Task Exception Message: One or more errors occurred.
'   Task Inner Exception Message: Something happened.

' Output when an OperationCanceledException or TaskCanceledException
' is thrown in the awaited method:
'   Exception Message: canceled
'   Task IsCanceled: True
'   Task IsFaulted:  False

Tratamento de várias exceções em métodos assíncronos

O exemplo a seguir ilustra a manipulação de exceção em que várias tarefas podem resultar em várias exceções. O bloco Try tem a expressão Await da tarefa retornada por Task.WhenAll. A tarefa é concluída quando as três tarefas às quais Task.WhenAll se aplica são concluídas.

Cada uma das três tarefas causa uma exceção. O bloco Catch itera por meio de exceções, que são encontradas na propriedade Exception.InnerExceptions da tarefa retornada por Task.WhenAll.

Public Async Function DoMultipleAsync() As Task
    Dim theTask1 As Task = ExcAsync(info:="First Task")
    Dim theTask2 As Task = ExcAsync(info:="Second Task")
    Dim theTask3 As Task = ExcAsync(info:="Third Task")

    Dim allTasks As Task = Task.WhenAll(theTask1, theTask2, theTask3)

    Try
        Await allTasks
    Catch ex As Exception
        Debug.WriteLine("Exception: " & ex.Message)
        Debug.WriteLine("Task IsFaulted: " & allTasks.IsFaulted)
        For Each inEx In allTasks.Exception.InnerExceptions
            Debug.WriteLine("Task Inner Exception: " + inEx.Message)
        Next
    End Try
End Function

Private Async Function ExcAsync(info As String) As Task
    Await Task.Delay(100)

    Throw New Exception("Error-" & info)
End Function

' Output:
'   Exception: Error-First Task
'   Task IsFaulted: True
'   Task Inner Exception: Error-First Task
'   Task Inner Exception: Error-Second Task
'   Task Inner Exception: Error-Third Task

Confira também