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 la instrucción Catch
son las menos específicas y catch todas las excepciones que deriven 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
esException
, 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:
Se encuentra una instrucción End en el bloque
Try
oCatch
.Se produce una excepción StackOverflowException en el bloque
Try
oCatch
.
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 catch 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 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 catch cualquier tipo de excepción, coloque la expresión Await
asociada a la tarea en un bloque Try
catch 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 catch las excepciones de seguridad que se producen antes de que se invoque al 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 que Try...Catch
catch antes de que el Sub
que contiene Process.Start
se inicie 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 catch una excepción que se aplica a una tarea asincrónica, la expresión Await
se encuentra en un bloque Try
del llamador 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