Sie sind auf Seite 1von 11

EXCEPCIONES

UNIVERSIDAD MARIANO GALVEZ – CAMPUS CENTRAL – Programación I – Lenguaje C# – Sección E


Primer Semestre – Ciclo 3 – Año 2018 – Ing. MBA. Juan Carlos Méndez N. Página 1 de 11

1. Introducción a las Excepciones


Una excepción ocurre en tiempo de ejecución (runtime) cuando la aplicación, en una
operación en particular, ha transcurrido a un estado anómalo o excepcional. Ese
estado anómalo lo podemos ejemplificar con la operación matemática de intento de
división por cero (que términos formales se categoriza como una operación indefinida
[sin significado]):

Este es el ejemplo más clásico de una operación aritmética que genera un estado
anómalo. Un ejemplo particular del error generado por el intento de dividir por cero lo
encontramos en la calculadora de Bing:

Más específicamente una operación inválida la definimos, en el contexto de C#, como:

• División entre cero.


• Acceso a un elemento de un arreglo (o colección) por debajo del límite inferior
(0), o por encima del límite superior (capacidad).
• Intento de escritura de un archivo inexistente en el sistema de archivos o en una
unidad de red.
• Conexión fallida a un servidor de base de datos.
• Argumento de método no inicializado (null).
• Superación del límite de memoria de trabajo.
• Entre muchas más...
EXCEPCIONES
UNIVERSIDAD MARIANO GALVEZ – CAMPUS CENTRAL – Programación I – Lenguaje C# – Sección E
Primer Semestre – Ciclo 3 – Año 2018 – Ing. MBA. Juan Carlos Méndez N. Página 2 de 11

Como ha sido mencionado, el lenguaje de programación C# provee las construcciones


sintácticas y semánticas para manejar o controlar las excepciones que se pudieran
generar en una sección o bloque de código específicos. Se tratan de las siguientes
palabras claves:

• try
• catch
• finally
• throw

2. Excepciones en C#
El lenguaje de programación C# permite controlar la generación de una excepción a
través de las construcciones try, catch, finally, y throw. La primera de estas -
try-, encierra el bloque de código que pudiera generar una excepción, si ocurriera
una excepción en el bloque try, el o los bloques catch se encargan de capturar la
excepción para un tratamiento o manejo específico a la excepción generada. Con
finally, se ejecutan operaciones una vez se finaliza el conjunto de sentencias
encerradas en el bloque try, o después de haber sido la excepción en un bloque
catch. (En las secciones posteriores nos detendremos en cada una de estas
construcciones para mostrar varios detalles importantes a la manejar una excepción.)

2.1 Omisión del control de excepciones


La máquina virtual CLR se encarga administrar las excepciones generadas por el código
propenso a generar situaciones inesperadas o anómalas: división entre cero, superación
de los límites de un arreglo, apertura de un archivo inexistente, &c.

Empecemos por explorar un ejemplo en donde no controlamos la división entre cero y


conocer los resultados:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication18
{
public sealed class SinControlExcepciones
{
public static int Dividir(int a, int b)
{
// La expresión `a / b` es propensa a generar la
// excepción de división entre cero:
EXCEPCIONES
UNIVERSIDAD MARIANO GALVEZ – CAMPUS CENTRAL – Programación I – Lenguaje C# – Sección E
Primer Semestre – Ciclo 3 – Año 2018 – Ing. MBA. Juan Carlos Méndez N. Página 3 de 11

return a / b;
}

public static void Main()


{
int num1 = 7;
int num2 = 0;

Console.WriteLine("\nLa división de {0} entre {1} es igual a


{2}\n", num1, num2, Dividir(num1, num2));
}
}
}

la CLR genera el siguiente mensaje de excepción:


Unhandled Exception: System.DivideByZeroException: Division by zero
at Articulos.Cap04.SinControlExcepciones.Main ()

Como resulta evidente, el mensaje coincide con la evaluación de una expresión que
incluye una división entre cero. El mensaje de excepción también nos indica que la
excepción no ha sido controlada o manejada (Unhandled Exception); además, de la
locación en donde se ha generado.
Finalmente, el programa finaliza su ejecución de forma abrupta, debido a que la
excepción no ha sido manejada.

2.2 Control de excepciones


Construyamos el código fuente necesario para controlar la excepción a través de las
construcciones mencionadas al principio de esta sección. Esto nos va a servir para
destacar las principales diferencias con el ejemplo presentando en la sección 2.1, y
empezar a concebir los esenciales del manejo de excepciones en C#.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication18
{
public sealed class ControlDEExcepciones
{
public static int Dividir(int a, int b)
{
EXCEPCIONES
UNIVERSIDAD MARIANO GALVEZ – CAMPUS CENTRAL – Programación I – Lenguaje C# – Sección E
Primer Semestre – Ciclo 3 – Año 2018 – Ing. MBA. Juan Carlos Méndez N. Página 4 de 11

if (b == 0)
{
throw new DivideByZeroException();
}

return a / b;
}

public static void Main()


{
int num1 = 7;
int num2 = 0;
int resultado;

try
{
resultado = Dividir(num1, num2);
Console.WriteLine("\nLa división de {0} entre {1} es
igual a {2}\n", num1,
num2, resultado);
}
catch (DivideByZeroException e)
{
Console.WriteLine("\nIntento de división entre 0\n");
Console.ReadKey();
}
}
}
}

En el método Dividir validamos que el divisor sea igual a cero, de ser así, entonces
lanzamos la excepción DividyByZeroException a través de la sentencia:

throw new DivideByZeroException();

En caso que el divisor sea distinto de cero, entonces se realiza la operación de división
de manera normal.

3. Construcciones de Manejo de Excepciones


Esta es la estructura general del manejo de excepciones en C#:
EXCEPCIONES
UNIVERSIDAD MARIANO GALVEZ – CAMPUS CENTRAL – Programación I – Lenguaje C# – Sección E
Primer Semestre – Ciclo 3 – Año 2018 – Ing. MBA. Juan Carlos Méndez N. Página 5 de 11

Try
{
... // sección de código propensa a generar excepciones
}

catch (ExceptionA ex)


{
// Manejo de la excepción de tipo ExceptionA
}

catch (ExceptionA ex)


{
// Manejo de la excepción de tipo ExceptionB
}

finally
{
// código de liberación de recursos
}

y continuación profundizaremos en detalles de cada elemento integral de este bloque


de código.

3.1 try-catch
La sentencia try-catch está compuesta por un bloque de sentencias proclives a
generar situaciones inesperadas o excepcionales; este bloque (try) se encierra entre
corchetes ({, y }), y va seguido por una o más clausulas catch. Cada una de las
clausulas corresponde con un tipo de excepción. Debido a que las excepciones
integradas en la biblioteca base de clases y las creadas por el propio programador
derivan de la clase base System.Exception , el orden (arriba-abajo) en que deben
organizarse las excepciones ha de empezar por el tipo de excepción más específico (o
con el orden jerarquía menor).

Continuando, el bloque try contiene la sentencia o el conjunto de sentencias


proclives a generar una excepción. En este bloque pueden ocurrir dos situaciones:

1. El bloque genera una excepción.


2. Finaliza satisfactoriamente y pasa al bloque finally (si ha sido declarado) o la
sentencia inmediata después del bloque try.
EXCEPCIONES
UNIVERSIDAD MARIANO GALVEZ – CAMPUS CENTRAL – Programación I – Lenguaje C# – Sección E
Primer Semestre – Ciclo 3 – Año 2018 – Ing. MBA. Juan Carlos Méndez N. Página 6 de 11

Asumamos el siguiente fragmento de código:

object o = null;

try
{
int i = (int) o; // Error
}

El intento de la operación unboxing en la sentencia encerrada por el bloque try,


generará la excepción NullReferenceException debido al intento de realizar una
operación sobre una referencia null. Esta excepción detendrá abruptamente la
ejecución de la aplicación; para evitar esto, se debe atrapar la excepción en un bloque
catch. Esta captura debe coincidir con un tipo específico o general de la jerarquía de
herencia. Así:

object o = null;

try
{
int i = (int) o; // Error
}
catch (InvalidCastException e)
{
Console.WriteLine ("Intento de conversión inválido.");
}

La clausula catch captura una excepción de tipo InvalidCastException . Esta


captura es tratada en el bloque subsiguiente; en donde podemos mostrar mensajes de
error y/o crear un archivo de registro de los problemas generados en el flujo de
ejecución de la aplicación.

Un bloque try, puede estar seguido por una o más clausulas y deben seguir el orden
(arriba-abajo) de tipos de excepciones específicos a más generales. El compilador de
EXCEPCIONES
UNIVERSIDAD MARIANO GALVEZ – CAMPUS CENTRAL – Programación I – Lenguaje C# – Sección E
Primer Semestre – Ciclo 3 – Año 2018 – Ing. MBA. Juan Carlos Méndez N. Página 7 de 11

C#, generará un error al declarar una clausula catch con un tipo general y más
adelante uno específico. Con un ejemplo queda más claro:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication18
{
public sealed class OrdenCatch
{
public static void Main()
{
object o = null;

try
{
int i = (int)o;
}
catch (Exception e)
{
//...
}
catch (InvalidCastException e)
{
//...
}
}
}
}

3.1.1 Prueba de la CLR cuando se genera una excepción


Cuando una excepción se genera y es lanzada desde cualquier lugar, la CLR lleva a
cabo la siguiente validación:

¿El flujo de ejecución se haya dentro de una sentencia try es proclive a lanzar una
excepción?
EXCEPCIONES
UNIVERSIDAD MARIANO GALVEZ – CAMPUS CENTRAL – Programación I – Lenguaje C# – Sección E
Primer Semestre – Ciclo 3 – Año 2018 – Ing. MBA. Juan Carlos Méndez N. Página 8 de 11

• En caso de ser así, el tratamiento de la excepción será llevado por la clausula


catch compatible con la excepción. Cuando la clausula catch finaliza
satisfactoriamente, el flujo de ejecución transita a la siguiente sentencia
después de la sentencia try-catch, o de haber un bloque finally se ha de
ejecutar este primero.
• En caso de no ser así, el flujo de ejecución pasa (esto sin antes ejecutar el
bloque finally) a la sección que invocó la función (e.g., propiedad, método) y
la prueba se repite de nuevo.

3.1.2 Captura de excepciones con System.Exception


Con el tipo de excepción System.Exception se captura cualquier tipo de excepción
que produzca dentro de la sentencia try. indican que esto es útil en las siguientes
situaciones:

• Recuperación de la ejecución del programa independiente del tipo específico


que se haya generado.
• Volver a lanzar la excepción, lo anterior sin antes crear un registro.
• Último recurso del manejador de errores antes de la terminación del programa.

3.1.3 Omisión de tipo de excepción y variable


Es posible prescindir de la variable dentro la clausula catch. Por ejemplo:

catch (DivideByZero)
{
// ...
}

Esto resulta útil cuando es necesario acceder a la información de la excepción (e.g.,


mensaje de error, ubicación exacta donde se generó la excepción). E inclusive se
puede prescindir también del tipo de la excepción. Así:

catch ()
{
// ...
}
Este tipo de clausula catch, atrapará cualquier tipo de excepción generada en el
bloque try subyacente.
EXCEPCIONES
UNIVERSIDAD MARIANO GALVEZ – CAMPUS CENTRAL – Programación I – Lenguaje C# – Sección E
Primer Semestre – Ciclo 3 – Año 2018 – Ing. MBA. Juan Carlos Méndez N. Página 9 de 11

3.2 El bloque finally


Esta sección opcional de la sentencia try-catch se ejecutará independiente de si se
ha completado satisfactoriamente el bloque try (es decir, sin generar ninguna
excepción), como no (es decir cuando alguno de los bloques catch ha atrapado
(capturado) una excepción.

En general, el bloque finally se ejecutan en cualquier de las siguientes situaciones:

• Al finalizar el bloque try.


• Uso de las sentencias de salto (e.g., goto o return) localizadas en el bloque
try.
• Después de finalizar un bloque catch.

las situaciones que pueden impedir el paso al bloque finally son un ciclo infinito,
o la terminación abrupta (e.g., desbordamiento de memoria) del programa.

El bloque finally ayuda a agregar determinismo al programa, es decir, que las


causas o razones producidas en la sentencia try-catch, luego sus efectos sean
tratados en el bloque finally.

En el siguiente ejemplo, aseguramos el cierre del archivo al finalizar la ejecución del


conjunto de sentencias del bloque try, o la generación de una excepción (i.e.,
IOException ), o si se alcanza el final del archivo o está vacío (EndOfStream):

public void LeerArchivo()


{
StreamReader sr = null;

try
{
sr = File.OpenText ("archivo.txt");

if (sr.EndOfStream)
{
return;
}

Console.WriteLine (sr.ReadToEnd());
}
EXCEPCIONES
UNIVERSIDAD MARIANO GALVEZ – CAMPUS CENTRAL – Programación I – Lenguaje C# – Sección E
Primer Semestre – Ciclo 3 – Año 2018 – Ing. MBA. Juan Carlos Méndez N. Página 10 de 11

finally
{
if (reader != null )
{
if (reader != null )
}
}
}

4. Sentencia using
Aquellas clases que implementan la interfaz System.IDisposable encapsulan
recursos no administrador por la CLR, como: archivos, gráficos, o bases de datos. Estas
clases implementan al método abstracto Dispose para la liberación de los recursos
(e.g., memoria) ocupados en su manejo. Para este tipo de clases, la sentencia
using provee una sintaxis más cómoda y versatil que usar la sentencia try-catch-
finally.

En lugar de
StreamReader sr = File.OpenText ("archivo.txt");

try
{
// ...
}
finally
{
if (sr != null)
{
((IDisposable)sr).Dispose();
}
}

podemos usar la sentencia using:


using (StreamReader sr = File.Open ("archivo.txt"));
{
EXCEPCIONES
UNIVERSIDAD MARIANO GALVEZ – CAMPUS CENTRAL – Programación I – Lenguaje C# – Sección E
Primer Semestre – Ciclo 3 – Año 2018 – Ing. MBA. Juan Carlos Méndez N. Página 11 de 11

// ...
};

Es evidente que este último modo es más cómodo, pues nos ahorra la liberación de
recursos por parte nuestra.

Resumen
Las excepciones cuentan con las siguientes características o propiedades :

• Todas las excepciones en el Framework .NET derivan de la clase


System.Exception.
• Use la sentencia try con la(s) sentencia(s) que sean proclives a generar
excepciones.
• Cuando ocurre una excepción dentro de un bloque try, esta es capturada por la
primera sentencia catch que es capaz de manejar la excepción.
• En caso de carecer de una sentencia capaz de manejar la excepción, el
programa terminará abruptamente arrojando un mensaje de error.
• Si en un bloque catch se define una variable del tipo de la excepción capturada
(atrapada), el programador puede utilizar esa información para dar detalles de
la excepción ocurrida.
• Para generar una excepción de forma explícita, use la palabra clave throw.
• El código que hace parte de un bloque finally se ejecuta independiente de si
el bloque try se ha completado satisfactoriamente o no.
• Las excepciones administradas en el Framework .NET se implementan bajo el
mecanismo de manipulación de excepciones Win32.

Das könnte Ihnen auch gefallen