Os explicamos cómo funciona el manejo de errores o excepciones en Visual Basci .Net, lenguaje de programación visual de Microsoft perteneciente a Visual Studio .Net. Os explicamos con ejemplos cómo capturar los posibles errores que se puedan producir en la ejecución normal del código para mostrar mensajes al usuario (o para que el usuario no se entere del error).
- Manejo de errores en versiones anteriores de Visual Basic.
- El objeto Exception en Visual Basic .NET.
- La instrucción Try…Catch…End Try ó Finally en Visual Basic .NET.
Manejo de errores en versiones anteriores de Visual Basic
En versiones anteriores de Visual Basic, como la versión 6, el control de errores se realizaba mediante:
1 2 3 4 5 6 7 8 9 10 |
On Error GoTo cError .... :cSalir exit sub :cError msgbox "Número de error: " + err.number + vbcrlf + _ " Descripción del error: " + err.description |
o bien utilizando «On Error Resume Next».
Visual Basic .Net sigue permitiendo el uso de estas dos instrucciones para el control de errores, pero Microsoft recomienda encarecidamente que no se utilicen y se empleen las nuevas instrucciones Try…Catch…Finally.
El objeto Exception en Visual Basic .NET
El objeto Exception se encuentra definido en .NET Framework y su nombre completo es System.Exception. En este marco de trabajo se definen otras dos clases genéricas: System.SystemException y System.ApplicationException. Casi todos los objetos de Exception definidos en .NET Framework heredan de SystemException, mientras que los objetos de excepción personalizados y específicos de cada aplicación heredan de ApplicationException. Estas dos clases no agregan ninguna propiedad o método a la clase base Exception.
A continuación enumeramos algunas de las clases Exception en los espacios de nombres más importantes de .NET Framework:
Espacios de nombre | Clases de excepción |
System | ArgumentNullException, ArgumentOutOfRangeException, DivideByZeroException, IndexOutOfRangeException, NullReference-Exception, OverflowException, StackOverflowException |
System.IO | DirectoryNotFoundException, EndOfStreamException, FileNotFoundException, PathTooLongException, FileLoadException, DriveNotFoundException |
System.Data | DuplicateNameException, InvalidConstraintException, InvalidExpressionException, MissingPrimaryKeyException, NoNullAllowedException, ReadOnlyException |
System.Runtime.InteropServices | InvalidComObjectException, InvalidOleVariantTypeException, SEHException |
La instrucción Try…Catch…End Try ó Finally en Visual Basic .NET
La palabra clave Catch
Siempre que se añada código fuente que pueda iniciar una excepción será conveniente introducirlo en un bloque Try…Catch…End. El código que quede entre Try y Catch estará protegido contra excepciones y si se iniciara una excepción, Visual Basic pasaría el control al primer bloque Catch (filtro de excepciones). En el bloque de código Catch se podrán examinar las propiedades del objeto Exception y decidir cómo reaccionar al error.
Un ejemplo sencillo de control de excepciones:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Private Sub btExcepcion_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btExcepcion.Click Dim x, y As Integer Try y = CInt(InputBox("Introduzca Y", "Control de excepciones", 0)) x = x y 'Si "y" = 0, la siguiente instrucción no se ejecutará y = CInt(10 ^ x) MsgBox("El valor de Y es: " + CStr(y)) Catch ex As Exception If ex.Message = "Intento de dividir por cero." Then MsgBox("Error al intentar dividir por cero.", _ MsgBoxStyle.Critical + MsgBoxStyle.OkOnly) Else MsgBox("Se ha producido el siguiente error: " + ex.Message, _ MsgBoxStyle.Critical + MsgBoxStyle.OkOnly) End If End Try End Sub |
En el ejemplo anterior se pide con un InputBox el valor de «y», se pueden dar varios casos según el valor introducido:
- Si el valor de «y» es igual a cero se producirá un error (se iniciará una excepción), puesto que tenemos control de excepciones, en este caso no se ejecutará la línea de código y = CInt (10 ^ x), en su lugar se captura el error y Visual Basic pasará el control al bloque Catch, puesto que se ha introducido un cero en «y», se ejecutará la línea que hay a continuación de If ex.Message = «Intento de dividir por cero.» Then. Tras ejecutar este código saltará a la siguiente instrucción a la línea «End Try» (si la hay).
- Si el valor de «y» es cualquier otro número distinto de cero no se producirá error por lo que se ejecutarán las líneas de código:
1 2 |
y = CInt(10 ^ x) MsgBox("El valor de Y es: " + CStr(y)) |
- Si el valor de «y» es un número no entero (Integer) o una cadena de texto se producirá un error y el programa saltará al bloque Catch, en este caso se ejecutará la línea de código siguiente al «Else» del bloque Catch y se mostrará un mensaje de error como el siguiente:
La forma anterior no es la adecuada para tratar las excepciones, pues se está comprobando el contenido de la cadena Message, que contiene la descripción del mensaje de error que se haya producido. La forma adecuada es que existan varios bloques Catch, cada uno de los cuales comprobará un objeto Exception distinto, según el código que introduzcamos entre el Try y los Catch. Por ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Private Sub btExcepcion_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btExcepcion.Click Dim x, y As Integer Try y = CInt(InputBox("Introduzca Y", "Control de excepciones", 0)) x = x y 'Si "y" = 0, la siguiente instrucción no se ejecutará y = CInt(10 ^ x) MsgBox("El valor de Y es: " + CStr(y)) Catch ex As DivideByZeroException MsgBox("Error al intentar dividir por cero.", _ MsgBoxStyle.Critical + MsgBoxStyle.OkOnly) Catch ex As OverflowException MsgBox("Error de desbordamiento, número muy grande.", _ MsgBoxStyle.Critical + MsgBoxStyle.OkOnly) Catch ex As Exception MsgBox("Se ha producido el siguiente error: " + ex.Message, _ MsgBoxStyle.Critical + MsgBoxStyle.OkOnly) End Try End Sub |
En el ejemplo anterior los posibles errores (excepciones) están correctamente capturados. Se pueden dar varios casos:
- Si el valor de «y» es cero el programa saltará a los bloques Catch y, puesto que se producirá una excepción de tipo DivideByZeroException, se ejecutará el código que haya en el primer Catch.
- Si el valor de «y» es un número muy grande el programa saltará a los bloques Catch y, puesto que se producirá una excepción de tipo OverflowException, se ejecutará el código que haya en el segundo Catch.
- Si el valor de «y» es un texto (por ejemplo) el programa saltará a los bloques Catch y, puesto que se producirá una excepción de tipo diferente a DivideByZeroException y OverflowException, se ejecutará el código que haya en el tercer Catch.
Visual Basic comparará el tipo de objeto Exception que se haya iniciado con las expresiones contenidas en las cláusulas Catch en el orden en el que aparecen y ejecutará la primera que coincida. Es importante contar siempre con una expresión Catch final que coincida con el objeto System.Exception, como mostramos en el ejemplo anterior, porque este código siempre se ejecutará en el caso de que ninguna de las expresiones Catch anteriores coincidan con la excepción producida. Una cláusula Catch del objeto System.Exception siempre coincidirá con cualquier excepción porque todos los objetos Exception heredan de System.Exception.
Como todas las expresiones Catch se evalúan en el orden en que aparecen, es recomendable comprobar las excepciones más específicas en primer lugar, en el ejemplo en primer lugar hemos colocado DivideByZeroException. Como hemos dicho, la comprobación del objeto System.Exception deberá estar en el último bloque Catch porque coincidirá con cualquier excepcion. Por ello, ningún bloque Catch situado detrás de de esta comprobación se ejecutará jamás. Además, cuando se ordenen los bloques Catch, se deberá tener en cuenta la jerarquía de excepciones y comprobar que nunca va a intentar capturar un objeto Exception después de capturar a su excepción padre. Por ejemplo, el bloque Catch correspondiente al objeto DivideByZeroException nunca deberá encontrarse a continuación del objeto ArithmeticException que resulta menos específico.
Siempre se podrá salir de la estructura Try…End Try con la instrucción Exit Try, que puede insertarse dentro de un bloque Try o en cualquier bloque Catch.
La palabra clave When
Dentro de la cláusula Catch se podrá utilizar una expresión When opcional que le permitirá especificar una condición adicional que el bloque Catch deberá evaluar como True para que sea seleccionada. Esta característica permitirá definir filtros de excepciones más específicos.
La palabra clave Finally
En determinadas ocasiones es necesario ejecutar un código de limpieza cuando se produce una excepción. Por ejemplo para cerrar un fichero abierto en el caso en que se produzca un error, o para cerrar la conexión con una base de datos. En estos casos en los que queremos ejecutar. Usando la claúsula Finally, el código que coloquemos en ella siempre se ejecutará, tanto si se produce error como si no.