30 octubre 2007

Como manejar excepciones en Delphi (y II)

Una vez que hemos visto lo que es una excepción y cómo proteger nuestro código usando bloques protegidos vamos a pasar a ver como pueden meterse unas excepciones dentro de otras para dar más seguridad a nuestro código. Es lo que se llaman excepciones anidadas.

EXCEPCIONES ANIDADAS

Vamos a ver un ejemplo de como anidar una excepción dentro de otra:

var
F: TextFile;
begin
AssignFile( F, 'C:\noexiste.txt' );

try
Reset( F );

try
CloseFile( F );
except
on E: Exception do
ShowMessage( 'Excepción 2: ' + E.Message );
end;

except
on E: Exception do
ShowMessage( 'Excepción 1: ' + E.Message );
end;
end;

En este ejemplo hemos metido un bloque protegido dentro de otro, donde cada uno controla su propia excepción. En este caso provocaría la excepción 1 ya que el archivo no existe.

DETENIENDO LA EXCEPCION

Cuando se provoca una excepción, una vez la hemos procesado con la sentencia on E: Exception, la ejecución continua hacia el siguiente bloque de código. Si queremos detener la ejecución del programa debemos utilizar el comando raise:

var
F: TextFile;
begin
AssignFile( F, 'C:\noexiste.txt' );
ShowMessage( '1' );

try
Reset( F );

except
on E: Exception do
raise;
end;

ShowMessage( '2' );
end;

En este ejemplo nunca llegaría a ejecutarse el segundo ShowMessage ya que raise detiene la ejecución del procedimiento.

FORZANDO A QUE FINALICE LA EJECUCION

Hay bloques de código en los cuales cuando se provoca una excepción ni podemos continuar con la ejecución ni podemos cortar la ejecución. Por ejemplo, supongamos que abro un archivo en módo sólo lectura e intento escribir en el mismo. Esto provocaría una excepción, pero lo que no puedo hacer es detener en seco la ejecución del programa ya que hay que cerrar el archivo que hemos abierto.

Para solucionar esto, los bloques protegidos permiten finalizar la ejecución en el caso de que se produzca una excepción mediante la claúsula finally. En nuestro ejemplo nos interesa que se cierre el archivo abierto:

var
F: TextFile;
begin
AssignFile( F, 'C:\prueba.txt' );

try
Reset( F );

try
WriteLn( F, 'intentando escribir' );
finally
ShowMessage( 'Finalizando...' );
CloseFile( F );
end;

except
on E: Exception do
raise;
end;
end;

Tenemos dos excepciones anidadas: una para abrir el archivo con una sentencia except que detiene la ejecución y otra dentro que utiliza la sentencia finally para cerrar el archivo en el caso de que se produzca un error.

TRATANDO EXCEPCIONES EN COMPONENTES VCL

Los componentes VCL también pueden provocar muchas excepciones si no sabemos utilizarlos correctamente. Un error típico es el intentar acceder a un elemento que no existe dentro de un componente ListBox llamado Lista:

begin
Lista.Items.Add( 'PABLO' );
Lista.Items.Add( 'MARIA' );
Lista.Items.Add( 'CARLOS' );

try
ShowMessage( Lista.Items[4] );
except
on E: EStringListError do
ShowMessage( 'La lista sólo tiene tres elementos.' );
end;
end;

En este caso se ha provocado una excepción de la clase EStringListError, aunque bien se podría haber controlado de este modo:

try
ShowMessage( Lista.Items[4] );
except
on E: Exception do
ShowMessage( 'La lista sólo tiene tres elementos.' );
end;

Los componentes VCL disponen principalmente de estas clases de excepciones:

EAbort: Finaliza la secuencia de eventos sin mostrar el mensaje de error.

EAccessViolation: Comprueba errores de acceso a memoria inválidos.

EBitsError: Previene intentos para acceder a arrays de elementos booleanos.

EComponentError: Nos informa de un intento inválido de registar o renombar un componente.

EConvertError: Muestra un error al convertir objetos o cadenas de texto string.

EDatabaseError: Especifica un error de acceso a bases de datos.

EDBEditError: Error al introducir datos incompatibles con una máscara de texto.

EDivByZero: Errores de división por cero.

EExternalException: Significa que no reconoce el tipo de excepción (viene de fuera).

EIntOutError: Representa un error de entrada/salida a archivos.

EIntOverflow: Especifica que se ha provocado un desbordamiento de un tipo de dato.

EInvalidCast: Comprueba un error de conversión de tipos.

EInvalidGraphic: Indica un intento de trabajar con gráficos que tienen un formato desconocido.

EInvalidOperation: Ocurre cuando se ha intentado realizar una operación inválida sobre un componente.

EInvalidPointer: Se produce en operaciones con punteros inválidos.

EMenuError: Controla todos los errores relacionados con componentes de menú.

EOleCtrlError: Detecta problemas con controles ActiveX.

EOleError: Especifica errores de automatización de objetos OLE.

EPrinterError: Errores al imprimir.

EPropertyError: Ocurre cuando se intenta asignar un valor erroneo a una propiedad del componente.

ERangeError: Indica si se intenta asignar un número entero demasiado grande a una propiedad.

ERegistryExcepcion: Controla los errores en el resigtro.

EZeroDivide: Controla los errores de división para valores reales.

EXCEPCIONES SILENCIOSAS

Para dar un toque profesional a un programa hay ocasiones en que nos interesa controlar la excepción pero que no se entere el usuario del programa. Lo que no se puede hacer es abandonar la excepción con los comandos Break o con Exit ya que puede ser peor el remedio que la enfermedad.

Para salir elegantemente de una excepción hay que utilizar el comando Abort:

try
{ sentencias }
except
Abort;
end;

De este modo se controla la excepción y el usuario no ve nada en pantalla.

Con esto finalizamos el tratamiento de excepciones en Delphi.

Pruebas realizadas en Delphi 7.

1 comentario:

elpatas dijo...

Muchas gracias, estoy probando con un pequeño programa que hace test a la conexion a BD, esto me ha servido

Publicidad