Try...Catch...Finally Instrucción (Visual Basic)

Proporciona un medio para controlar una parte o la totalidad de los posibles errores que pueden producirse en un bloque de código determinado, mientras se sigue ejecutando el código.

Sintaxis

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

Partes

Término Definición
tryStatements Opcional. Instrucciones donde puede producirse un error. Puede ser una instrucción compuesta.
Catch Opcional. Se permiten varios bloques Catch. Si se produce una excepción al procesar el bloque Try, cada instrucción Catch se examina en orden textual para determinar si controla la excepción, con exception representando la excepción que se ha producido.
exception Opcional. Cualquier nombre de variable. El valor inicial de exception es el valor del error producido. Se usa con Catch para especificar el error detectado. Si se omite, la instrucción Catch detecta cualquier excepción.
type Opcional. Especifica el tipo de filtro de clase. Si el valor de exception es del tipo especificado por type o de un tipo derivado, el identificador se enlaza al objeto de excepción.
When Opcional. Una instrucción Catch con una cláusula When detecta excepciones solo cuando expression se evalúa como True. Una cláusula When solo se aplica después de comprobar el tipo de la excepción y expression puede hacer referencia al identificador que representa la excepción.
expression Opcional. Debe poder convertirse implícitamente en Boolean. Cualquier expresión que describa un filtro genérico. Normalmente se usa para filtrar por número de error. Se usa con la palabra clave When para especificar las circunstancias en las que se detecta el error.
catchStatements Opcional. Instrucciones para controlar los errores que se producen en el bloque Try asociado. Puede ser una instrucción compuesta.
Exit Try Opcional. Palabra clave que se desglosa de la estructura Try...Catch...Finally. La ejecución se reanuda con el código inmediatamente después de la instrucción End Try. La instrucción Finally se seguirá ejecutando. No se permite en bloques Finally.
Finally Opcional. Siempre se ejecuta un bloque Finally cuando la ejecución sale de cualquier parte de la instrucción Try...Catch.
finallyStatements Opcional. Instrucciones que se ejecutan después de que se hayan procesado todos los demás errores.
End Try Finaliza la estructura Try...Catch...Finally.

Comentarios

Si espera que se produzca una excepción determinada durante una sección determinada del código, coloque el código en un bloque Try y use un bloque Catch para mantener el control y gestionar la excepción si se produce.

Una instrucción Try…Catch consta de un bloque Try seguido de una o más cláusulas Catch que especifican controladores para diferentes excepciones. Cuando se produce una excepción en un bloque Try, Visual Basic busca la instrucción Catch que controla la excepción. Si no se encuentra una instrucción coincidente Catch, Visual Basic examina el método que llamó al método actual, etc. sobre la pila de llamadas. Si no existe ningún bloque Catch, Visual Basic muestra al usuario un mensaje de excepción no controlada y detiene la ejecución del programa.

Puede usar más de una instrucción Catch en una instrucción Try…Catch. Si lo hace, el orden de las cláusulas Catch es significativo porque se examinan en orden. Catch detecta las excepciones más específicas antes que las menos específicas.

Las siguientes condiciones de instrucción Catch son las menos específicas y detectarán todas las excepciones derivadas de la clase Exception. Normalmente, debe usar una de estas variaciones como último bloque Catch de la estructura Try...Catch...Finally, después de detectar todas las excepciones específicas que espera. El flujo de control nunca puede alcanzar un bloque Catch que siga a cualquiera de estas variaciones.

  • type es Exception, por ejemplo: Catch ex As Exception

  • La instrucción no tiene ninguna variable exception, por ejemplo: Catch

Cuando una instrucción Try…Catch…Finally está anidada en otro bloque Try, Visual Basic examina primero cada instrucción Catch en el bloque Try más interno. Si no se encuentra ninguna instrucción Catch coincidente, la búsqueda continúa con las instrucciones Catch del bloque Try…Catch…Finally externo.

Las variables locales de un bloque Try no están disponibles en un bloque Catch porque son bloques independientes. Si quiere usar una variable en más de un bloque, declare la variable fuera de la estructura Try...Catch...Finally.

Sugerencia

La instrucción Try…Catch…Finally también está disponible como fragmento de código de IntelliSense. En el Administrador de fragmentos de código, expanda Patrones de código - If, For Each, TryCatch, Propiedad, etc. y, posteriormente, Control de errores (Excepciones). Para obtener más información, vea Fragmentos de código.

Bloque Finally

Si tiene una o varias instrucciones que deben ejecutarse antes de salir de la estructura Try, use un bloque Finally. El control pasa al bloque Finally justo antes de salir de la estructura Try…Catch. Esto es cierto incluso si se produce una excepción en cualquier parte de la estructura Try.

Un bloque Finally es útil para ejecutar cualquier código que se debe ejecutar incluso si se produce una excepción. El control se pasa al bloque Finally independientemente de cómo se cierra el bloque Try...Catch.

El código de un bloque Finally se ejecuta incluso si el código encuentra una instrucción Return en un bloque Try o Catch. El control no pasa de un bloque Try o Catch al bloque Finally correspondiente en los casos siguientes:

No es válido transferir explícitamente la ejecución a un bloque Finally. La transferencia de la ejecución fuera de un bloque Finally no es válida, excepto a través de una excepción.

Si una instrucción Try no contiene al menos un bloque Catch, debe contener un bloque Finally.

Sugerencia

Si no tiene que detectar excepciones específicas, la instrucción Using se comporta como un bloque Try…Finally y garantiza la eliminación de los recursos, independientemente de cómo salga del bloque. Esto es cierto incluso con una excepción no controlada. Para obtener más información, vea Using (Instrucción).

Argumento de excepción

El exception argumento del bloque Catch es una instancia de la clase Exception o una clase que deriva de la clase Exception. La instancia de clase Exception corresponde al error que se produjo en el bloque Try.

Las propiedades del objeto Exception ayudan a identificar la causa y la ubicación de una excepción. Por ejemplo, la propiedad StackTrace enumera los métodos llamados que llevaron a la excepción, para ayudarle a encontrar dónde se produjo el error en el código. Message devuelve un mensaje que describe la excepción. HelpLink devuelve un vínculo a un archivo de ayuda asociado. InnerException devuelve el objeto Exception que provocó la excepción actual o devuelve Nothing en ausencia de Exception original.

Consideraciones al usar una instrucción Try…Catch

Use una instrucción Try…Catch solo para indicar la aparición de eventos de programa inusuales o imprevistos. Entre las razones para hacerlo se incluyen las siguientes:

  • La detección de excepciones con Catch en tiempo de ejecución crea una sobrecarga adicional y es probable que sea más lenta que la comprobación previa para evitar excepciones.

  • Si un bloque Catch no se controla correctamente, es posible que la excepción no se notifique correctamente a los usuarios.

  • El control de excepciones hace que un programa sea más complejo.

No siempre necesita una instrucción Try…Catch para comprobar una condición que es probable que se produzca. En el ejemplo siguiente se comprueba si existe un archivo antes de intentar abrirlo. Esto reduce la necesidad de detectar una excepción producida por el 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

Asegúrese de que el código de los bloques Catch pueda notificar correctamente las excepciones a los usuarios, ya sea mediante el registro seguro para subprocesos o los mensajes adecuados. De lo contrario, es posible que las excepciones permanezcan desconocidas.

Métodos asincrónicos

Si marca un método con el modificador Async, puede usar el operador Await en el método. Una instrucción con el operador Await suspende la ejecución del método hasta que se completa la tarea esperada. La tarea representa el trabajo en curso. Cuando finaliza la tarea que está asociada al operador Await, la ejecución se reanuda en el mismo método. Para obtener más información, consulte Control Flow in Async Programs (Flujo de control en programas asincrónicos).

Una tarea devuelta por un método asincrónico puede terminar en un estado defectuoso, lo que indica que se completó debido a una excepción no controlada. Una tarea también puede terminar en un estado cancelado, lo que da lugar a que se produzca una excepción OperationCanceledException de la expresión Await. Para detectar cualquier tipo de excepción, coloque la expresión Await asociada a la tarea en un bloque Try y detecte la excepción en el bloque Catch. Más adelante en este tema se proporciona un ejemplo.

Una tarea puede estar en un estado defectuoso porque varias excepciones eran responsables de su error. Por ejemplo, la tarea podría ser el resultado de una llamada a Task.WhenAll. Cuando espera una tarea de este tipo, solo se captura una de las excepciones y no puede predecir qué excepción se capturará. Más adelante en este tema se proporciona un ejemplo.

Una expresión Await no puede estar dentro de un bloque Catch o un bloque Finally.

Iterators

Un función de iterador o un descriptor de acceso Get realiza una iteración personalizada en una colección. Un iterador usa una instrucción Yield para devolver cada elemento de la colección a la vez. Se llama a una función de iterador mediante una instrucción For Each...Next.

Una instrucción Yield puede estar dentro de un bloque Try. Un bloque Try que contiene una instrucción Yield puede tener bloques Catch y puede tener un bloque Finally. Para ver un ejemplo, consulte Bloques Try.

Una instrucción Yield no puede estar dentro de un bloque Catch o un bloque Finally.

Si el cuerpo de For Each (fuera de la función de iterador) produce una excepción, no se ejecuta un bloque Catch en la función de iterador, pero se ejecuta un bloque Finally en la función de iterador. Un bloque Catch dentro de una función de iterador detecta solo las excepciones que se producen dentro de la función de iterador.

Situaciones de confianza parcial

En situaciones de confianza parcial, como una aplicación hospedada en un recurso compartido de red, Try...Catch...Finally no detecta las excepciones de seguridad que se producen antes de invocar el método que contiene la llamada. En el ejemplo siguiente, cuando se coloca en un recurso compartido de servidor y se ejecuta desde allí, se produce el error "System.Security.SecurityException: Error de solicitud". Para obtener más información acerca de las excepciones de seguridad, consulte la clase SecurityException.

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

En esta situación de confianza parcial, debe colocar la instrucción Process.Start en un elemento independiente Sub. Se producirá un error en la llamada inicial a Sub. Esto permite a Try...Catch detectarlo antes de que se inicie Sub que contiene Process.Start y se produzca la excepción de seguridad.

Ejemplos

Estructura de Try...Catch...Finally

En el siguiente ejemplo se muestra la estructura de la instrucción 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

Excepción en un método llamado desde un bloque Try

En el ejemplo siguiente, el método CreateException produce una excepción NullReferenceException. El código que genera la excepción no está en un bloque Try. Por lo tanto, el método CreateException no controla la excepción. El método RunSample controla la excepción porque la llamada al método CreateException está en un bloque Try.

En el ejemplo se incluyen instrucciones Catch para varios tipos de excepciones, ordenadas de la más específica a la más general.

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

La instrucción Catch When

En el ejemplo siguiente se muestra cómo usar una instrucción Catch When para filtrar por una expresión condicional. Si la expresión condicional se evalúa como True, el código del bloque Catch se ejecuta.

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

Instrucciones anidadas de Try

En el ejemplo siguiente se incluye una instrucción Try…Catch contenida en un bloque Try. El bloque Catch interno produce una excepción que tiene su propiedad InnerException establecida en la excepción original. El bloque Catch externo notifica su propia excepción y la excepción 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

Control de excepciones para métodos asincrónicos

En el ejemplo siguiente se muestra el control de excepciones de los métodos asincrónicos. Para detectar una excepción que se aplica a una tarea asincrónica, la expresión Await se encuentra en un bloque Try del autor de la llamada y la excepción se detecta en el bloque Catch.

Quite la marca de comentario de la línea Throw New Exception en el ejemplo para demostrar el control de excepciones. La excepción se captura en el bloque Catch, la propiedad de la tarea IsFaulted se establece enTrue y la propiedad de la tarea Exception.InnerException se establece en la excepción.

Quite la marca de comentario de la línea Throw New OperationCancelledException para ver lo que pasa cuando se cancela un proceso asincrónico. La excepción se captura en el bloque Catch y la propiedad de la tarea IsCanceled se establece en True. En algunas condiciones que no son aplicables a este ejemplo, IsFaulted se establece en True y IsCanceled se establece en 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

Control de varias excepciones en métodos asincrónicos

En el ejemplo siguiente se muestra el control de excepciones en el que varias tareas pueden producir varias excepciones. El bloque Try tiene la expresión Await para la tarea que Task.WhenAll devuelve. La tarea se completa cuando se hayan completado las tres tareas a las que se aplica Task.WhenAll.

Cada una de las tres tareas produce una excepción. El bloque Catch se itera a través de las excepciones, que se encuentran en la propiedad Exception.InnerExceptions de la tarea devuelta 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

Consulte también