Ejercicio: Detección de tipos de excepciones específicos
Anteriormente en este módulo, ha aprendido que los objetos de excepción detectados por la aplicación de C# son instancias de una clase de excepción. Por lo general, el código catch será uno de los siguientes:
- Objeto de excepción que es una instancia de la
System.Exceptionclase base. - Objeto de excepción que es una instancia de un tipo de excepción que hereda de la clase base. Por ejemplo, una instancia de la
InvalidCastExceptionclase .
Examen de las propiedades de excepción
System.Exception es la clase base de la que heredan todos los tipos de excepción derivados. Cada tipo de excepción hereda de la clase base a través de una jerarquía de clases específica. Por ejemplo, la jerarquía de clases de InvalidCastException es la siguiente:
Object
Exception
SystemException
InvalidCastException
La mayoría de las clases de excepción que heredan de Exception no agregan ninguna funcionalidad adicional; simplemente heredan de Exception. Por lo tanto, examinar las propiedades de la Exception clase permite comprender la mayoría de las excepciones y cómo puede usar una excepción en su código.
Estas son las propiedades de la Exception clase :
- Datos: la
Datapropiedad contiene datos arbitrarios en pares clave-valor. - HelpLink: la
HelpLinkpropiedad se puede usar para contener una dirección URL (o URN) en un archivo de ayuda que proporciona información extensa sobre la causa de una excepción. - HResult: la
HResultpropiedad se puede usar para tener acceso a un valor numérico codificado asignado a una excepción específica. - InnerException: la
InnerExceptionpropiedad se puede usar para crear y conservar una serie de excepciones durante el control de excepciones. - Mensaje: La
Messagepropiedad proporciona detalles sobre la causa de una excepción. - Origen: la
Sourcepropiedad se puede usar para tener acceso al nombre de la aplicación o al objeto que provoca el error. - StackTrace: la
StackTracepropiedad contiene un seguimiento de pila que se puede usar para determinar dónde se produjo un error. - TargetSite: la
TargetSitepropiedad se puede usar para obtener el método que produce la excepción actual.
No te preocupes si te sientes un poco abrumado por este análisis de las características excepcionales, las clases base y la herencia. No se preocupe, detectar excepciones en el código y acceder a las propiedades de una excepción es más fácil que explicar cómo funcionan las excepciones y las propiedades de excepción.
Nota:
En este módulo, se centrará en usar la propiedad message de una excepción para notificar la excepción en la interfaz de usuario de la aplicación.
Acceso a las propiedades de un objeto de excepción
Ahora que comprende los objetos de excepción y sus propiedades, es el momento de empezar a codificar.
Actualice el archivo Program.cs de la manera siguiente:
try { Process1(); } catch { Console.WriteLine("An exception has occurred"); } Console.WriteLine("Exit program"); static void Process1() { try { WriteMessage(); } catch { Console.WriteLine("Exception caught in Process1"); } } static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; Console.WriteLine(float1 / float2); Console.WriteLine(number1 / number2); }Tómese un minuto para revisar el código.
Este es el mismo código que vio en la unidad anterior (el código de solución para la actividad de desafío). Sabe que se produce una excepción durante el
WriteMessagemétodo . También sabe que la excepción se detecta en el métodoProcess1. Usará este código para examinar objetos de excepción y tipos de excepción específicos.Actualice el método
Process1de la manera siguiente:static void Process1() { try { WriteMessage(); } catch (Exception ex) { Console.WriteLine($"Exception caught in Process1: {ex.Message}"); } }Dedique un minuto a examinar las actualizaciones.
Observe que la cláusula actualizada
catchdetecta una instancia de laExceptionclase en un objeto denominadoex. Observe también que elConsole.WriteLine()método usaexpara acceder a la propiedad delMessageobjeto y mostrar el mensaje de error en la consola.Aunque la
catchcláusula se puede usar sin argumentos, no se recomienda ese enfoque. Si no especifica un argumento, se capturan todos los tipos de excepción y no se puede distinguir entre ellos.En general, solo debe detectar las excepciones de las que el código sabe cómo recuperarse. Por lo tanto, la
catchcláusula debe especificar un argumento de objeto derivado deSystem.Exception. El tipo de excepción debe ser lo más específico posible. Esto ayuda a evitar detectar excepciones que el controlador de excepciones no puede resolver. Actualizará el código para detectar un tipo de excepción específico más adelante en este ejercicio.En el menú Archivo, seleccione Guardar.
Establezca el punto de interrupción en la siguiente línea de código:
Console.WriteLine($"Exception caught in Process1: {ex.Message}");En el menú Ejecutar, seleccione Iniciar depuración.
La ejecución del código debe pausarse en el punto de interrupción.
Mantenga el cursor del mouse sobre
ex.Observe que IntelliSense muestra las mismas propiedades de excepción que ha examinado anteriormente.
Dedique un minuto a examinar la información que describe el objeto
exde excepción .Observe que la excepción es de tipo
System.DivideByZeroExceptiony que la propiedadMessageestá establecida enAttempted to divide by zero..Observe que la
StackTracepropiedad notifica el método y el número de línea donde se produjo el error, junto con la secuencia de llamadas al método (y números de línea) que llevaron al error.En la barra de herramientas Depurar, seleccione Continuar.
Dedique un minuto a examinar la salida de la consola.
Observe que la propiedad de
Messagela excepción se incluye en la salida generada por la aplicación:∞ Exception caught in Process1: Attempted to divide by zero. Exit program
Detectar un tipo de excepción específico
Ahora que conoce el tipo de excepción que se va a detectar, puede actualizar la catch cláusula para controlar ese tipo de excepción específico.
Actualice el método
Process1de la manera siguiente:static void Process1() { try { WriteMessage(); } catch (DivideByZeroException ex) { Console.WriteLine($"Exception caught in Process1: {ex.Message}"); } }Guarde el código y, a continuación, inicie una sesión de depuración.
Observe que la aplicación actualizada notifica los mismos mensajes a la consola.
Aunque los mensajes notificados son los mismos, hay una diferencia importante. El
Process1método solo detectará excepciones del tipo específico que está preparado para controlar.Para generar un tipo de excepción diferente, actualice el método de la
WriteMessagesiguiente manera:static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; byte smallNumber; Console.WriteLine(float1 / float2); // Console.WriteLine(number1 / number2); checked { smallNumber = (byte)number1; } }Observe el uso de la instrucción
checked.Al realizar cálculos de tipos enteros que asignan el valor de un tipo entero a otro tipo entero, el resultado depende del contexto de comprobación de desbordamiento. En un
checkedcontexto, la conversión se realiza correctamente si el valor de origen está dentro del intervalo del tipo de destino. De lo contrario, se produce una excepciónOverflowException. En un contexto sin restricciones, la conversión siempre tiene éxito y continúa de la siguiente manera:Si el tipo de origen es más grande que el tipo de destino, el valor de origen se trunca descartando sus bits más significativos adicionales. El resultado se trata como un valor del tipo de destino.
Si el tipo de origen es más pequeño que el tipo de destino, entonces el valor de origen se amplía mediante extensión de signo o extensión con ceros para que tenga el mismo tamaño que el tipo de destino. La extensión de signo se usa si el tipo de origen es con signo; la extensión con ceros se usa si el tipo de origen es sin signo. El resultado se trata como un valor del tipo de destino.
Si el tipo de origen tiene el mismo tamaño que el tipo de destino, el valor de origen se trata como un valor del tipo de destino.
Nota:
Los cálculos de tipos enteros que no están dentro de un
checkedbloque de código se tratan como si estuvieran dentro de ununcheckedbloque de código.Guarde el código y, a continuación, inicie una sesión de depuración.
Observe que un nuevo tipo de excepción es detectado por la cláusula
catchen las instrucciones de nivel superior, en lugar de dentro del métodoProcess1.La aplicación imprime los siguientes mensajes en la consola:
∞ An exception has occurred Exit programNota:
El bloque
catchdeProcess1no se ejecuta. Este es el comportamiento que quería. Solo captura las excepciones que tu código esté preparado para manejar.
Detectar varias excepciones en un bloque de código
En este momento, es posible que se pregunte qué ocurre cuando se producen varias excepciones en un único bloque de código. ¿El código catch cada excepción a medida que se produzcan?
Actualice el método
WriteMessagede la manera siguiente:static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; byte smallNumber; Console.WriteLine(float1 / float2); Console.WriteLine(number1 / number2); checked { smallNumber = (byte)number1; } }Establezca el punto de interrupción dentro del
WriteMessage()método en la siguiente línea de código:Console.WriteLine(float1 / float2);Guarde el código y, a continuación, inicie una sesión de depuración.
Recorra el código una línea a la vez y observe lo que sucede después de que el código controle la primera excepción.
Cuando se produce la primera excepción, el control se pasa a la primera
catchcláusula que puede controlar la excepción. El código que generaría la segunda excepción nunca se ejecuta. Esto significa que parte del código nunca se ejecuta. Esto podría dar lugar a problemas graves.Dedique un minuto a tener en cuenta cómo puede administrar varias excepciones y cuándo o por qué no desea que el código administre varias excepciones.
Ha aprendido anteriormente en este módulo que las excepciones deben detectarse lo más cerca posible de dónde se producen. Teniendo esto en cuenta, puede optar por actualizar el método
WriteMessagepara detectar excepciones mediante su propiotry-catch. Por ejemplo:static void WriteMessage() { double float1 = 3000.0; double float2 = 0.0; int number1 = 3000; int number2 = 0; byte smallNumber; try { Console.WriteLine(float1 / float2); Console.WriteLine(number1 / number2); } catch (DivideByZeroException ex) { Console.WriteLine($"Exception caught in WriteMessage: {ex.Message}"); } checked { smallNumber = (byte)number1; } }También puede encapsular el código que provoca el
OverflowExceptiondentro de untry-catchindependiente dentro del métodoWriteMessage().checked { try { smallNumber = (byte)number1; } catch (OverflowException ex) { Console.WriteLine($"Exception caught in WriteMessage: {ex.Message}"); } }¿En qué condiciones no sería conveniente detectar excepciones posteriores?
Tenga en cuenta el caso cuando el método (o bloque de código) complete un proceso de dos partes. Supongamos que la segunda parte del proceso depende de la primera parte que se complete. Si la primera parte del proceso no se puede completar correctamente, no hay ningún punto para continuar con la segunda parte del proceso. En este caso, a menudo es mejor presentar al usuario un mensaje que explique la condición de error sin intentar la parte o partes restantes del proceso mayor.
Detección de tipos de excepción diferentes en un bloque de código
Hay ocasiones en las que las variaciones de los datos pueden provocar distintos tipos de excepciones.
Borre los puntos de interrupción y reemplace el contenido del archivo Program.cs por el código siguiente:
// inputValues is used to store numeric values entered by a user string[] inputValues = new string[]{"three", "9999999999", "0", "2" }; foreach (string inputValue in inputValues) { int numValue = 0; try { numValue = int.Parse(inputValue); } catch (FormatException) { Console.WriteLine("Invalid readResult. Please enter a valid number."); } catch (OverflowException) { Console.WriteLine("The number you entered is too large or too small."); } catch(Exception ex) { Console.WriteLine(ex.Message); } }Dedique un minuto a revisar este código.
En primer lugar, el código crea una matriz de cadenas denominada
inputValues. Los datos de la matriz están diseñados para representar los valores de entrada especificados por un usuario que se indicó que escriba valores numéricos. Dependiendo del valor especificado, pueden producirse diferentes tipos de excepción.Observe que el código usa el
int.Parsemétodo para convertir los valores de cadena "input" en enteros. Elint.Parsecódigo se coloca dentro de untrybloque de código.Establezca un punto de interrupción en la siguiente línea de código:
int numValue = 0;Guarde el código y, a continuación, inicie una sesión de depuración.
Recorra el código una línea a la vez y observe que se detectan distintos tipos de excepción.
Resumen
Estos son algunos de los aspectos más importantes que debe recordar de esta unidad:
- La
catchcláusula debe configurarse para detectar un tipo de excepción específico. Por ejemplo, el tipo de excepciónDivideByZeroException. - Se puede acceder a las propiedades de un objeto de excepción dentro del
catchbloque . Por ejemplo, puede usar laMessagepropiedad para informar al usuario de la aplicación de un problema. - Puede especificar dos o más
catchcláusulas cuando necesite detectar más de un tipo de excepción.