Después de leer mi artículo "Cómo separar el código de interfaz y el código funcional (basado en Delphi/VCL)", alguien mencionó una pregunta: cómo manejar errores en las clases del lado del servidor.
En las estructuras basadas en funciones, generalmente usamos valores de retorno de funciones para indicar si la función se ejecutó correctamente y para brindar información como los tipos de error. Entonces habrá código en la siguiente forma:
RetVal := AlgunaFunciónToOpenFile();
si RetVal = E_SUCCESSED entonces
...
de lo contrario, si RetVal = E_FILENOTFOUND entonces
...
de lo contrario, si RetVal = E_FILEFORMATERR entonces
...
más entonces
...
Es muy común utilizar un método que devuelve un código de error, pero existen dos problemas al utilizar dicho método:
1. Crea una estructura de rama larga y complicada (una gran cantidad de declaraciones if o case), lo que complica el proceso de control.
2. Puede haber errores que no se hayan manejado (si el llamador de la función no determina el valor de retorno)
Las excepciones son una solución orientada a objetos para el manejo de errores. Puede informar errores, pero lo que necesita saber es que la excepción no se genera debido al error, sino simplemente porque se utiliza el aumento.
En Object Pascal, la palabra reservada elevada se utiliza para generar excepciones. En cualquier momento (incluso si no ocurre ningún error), el aumento provocará una excepción.
Las excepciones pueden hacer que el código regrese inmediatamente desde el punto donde ocurre la excepción, protegiendo así la ejecución del código confidencial a continuación. No hay diferencia entre regresar de una función a través de una excepción y regresar de una función normalmente (ejecutándose hasta el final de la función o ejecutando Salir) para la función misma que arroja la excepción. La diferencia es que al final de la persona que llama, después de regresar a través de una excepción, los derechos de ejecución serán capturados por el intento de la persona que llama... excepto los bloques (si existen). Si no hay ningún bloque try...except en la persona que llama, las declaraciones posteriores no continuarán ejecutándose, pero regresarán a la persona que llama de nivel superior hasta que se encuentre un bloque try...except que pueda manejar la excepción. Una vez manejada la excepción, las declaraciones después del bloque try...except continuarán ejecutándose y el control se deja en la capa que maneja la excepción. Cuando el controlador de excepciones siente que el manejo de la excepción no es lo suficientemente completo, necesita que la persona que llama de nivel superior continúe procesando. Puede volver a lanzar la excepción (use un aumento simple) y transferir el control a la persona que llama de nivel superior. .
Si no hay ningún intento... excepto el bloque preestablecido, la excepción final será detectada por el intento más externo... excepto el bloque de VCL que encapsula todo el programa.
Por lo tanto, no habrá excepciones no controladas, en otras palabras, no habrá errores no controlados (aunque los errores y las excepciones no se equiparan). Esta es también la ventaja del mecanismo de excepción sobre el uso de métodos que devuelven códigos de error. Además, después de que se lanza la excepción, la dirección del proceso de control es muy clara y no hará que el proceso pierda el control.
Para dar un ejemplo de cómo funcionan las excepciones, supongamos que queremos abrir un archivo en un formato específico:
Primero defina dos clases de excepción (heredadas de Exception)
EFileNotFound = clase(Excepción);
EFileFormatErr = clase(Excepción);
Supongamos que hay un botón en Form1 y al presionarlo se abre el archivo:
Procedimiento TForm1.Button1Click(Remitente: TObject);
comenzar
intentar
ParaAbrirArchivo();
excepto
en EFileNotFound hacer
ShowMessage('Lo siento, no puedo encontrar el archivo');
onEFileFormatErr hacer
ShowMessage('Lo siento, el archivo no es el que quiero');
en E:Excepción hacer
Mostrar mensaje (E.Mensaje);
fin;
fin;
Y la función para abrir el archivo:
procedimiento ToOpenFile;
varRetVal:Entero;
comenzar
// Algún código para abrir el archivo
RetVal := -1; //falló la apertura
si RetVal = 0 entonces //éxito
Salida
de lo contrario, si RetVal = -1 entonces
Levante EFileNotFound.Create('Archivo no encontrado')
de lo contrario, si RetVal = -2 entonces
Levante EFileFormatErr.Create('Error de formato de archivo')
else //otro error
Generar Exception.Create('Error desconocido');
fin;
En el programa, TForm1.Button1Click llama a ToOpenFile y preestablece el intento... excepto para manejar las excepciones que puede generar ToOpenFile. Por supuesto, el código de manejo de excepciones de TForm1.Button1Click también se puede simplificar:
procedimiento TForm1.Button1Click (Remitente: TObject);
comenzar
intentar
ParaAbrirArchivo();
excepto
ShowMessage('Error al abrir el archivo');
fin;
fin;
El uso de excepciones resuelve el problema del uso de métodos que devuelven códigos de error. Por supuesto, el uso de excepciones tiene un costo. Las excepciones aumentarán la carga del programa, por lo que no es aconsejable abusar de ellas. Hay una gran diferencia entre escribir unos pocos intentos... excepto y escribir miles de intentos... excepto. En palabras de Charlie Calverts: "Deberías utilizar el intento... excepto los bloques cuando parezca útil. Pero trata de no entusiasmarte demasiado con esta técnica".
Además, Object Pascal introduce una estructura única de intento...finalmente. Dije antes que no hay diferencia entre regresar de una función a través de una excepción y regresar de una función normalmente. Por lo tanto, los objetos locales en la pila de la función se liberarán automáticamente, pero los objetos en el montón no. Sin embargo, el modelo de objetos de Object Pascal se basa en referencias, que existen en el montón, no en la pila. Por lo tanto, a veces necesitamos limpiar algunos recursos de objetos locales antes de regresar de una función a través de una excepción. Inténtalo... finalmente resuelve este problema.
Reescribí el código ToOpenFile anterior, esta vez usando algunos recursos durante el proceso ToOpenFile y liberando estos recursos después de que ocurra (o no ocurra) la excepción antes de regresar de la función:
procedimiento ToOpenFile;
varRetVal: entero;
Corriente: TStream;
comenzar
// Algún código para abrir el archivo
Corriente := TStream.Create;
RetVal := -1; //falló la apertura
intentar
si RetVal = 0 entonces //éxito
Salida
de lo contrario, si RetVal = -1 entonces
Levante EFileNotFound.Create('Archivo no encontrado')
de lo contrario, si RetVal = -2 entonces
Levante EFileFormatErr.Create('Error de formato de archivo')
else //otro error
Generar Exception.Create('Error desconocido');
finalmente
Transmitir.Gratis;
fin;
fin;
Al revisar el código anterior, podemos ver que incluso cuando el valor de RetVal es 0, después de ejecutar Exit, el código finalmente se ejecutará y luego regresará de la función. Esto asegura la correcta liberación de los recursos locales.
Los propósitos y escenarios de uso de try...except y try...finally son diferentes y muchos principiantes los confunden. Lo siguiente es un conocimiento personal del autor: try...except es generalmente utilizado por la persona que llama para capturar excepciones lanzadas por las funciones llamadas y manejarlas. Y probar... finalmente se usa generalmente para la función que genera la excepción para realizar algún trabajo de limpieza de recursos.
La programación orientada a objetos proporciona una solución de manejo de errores llamada "excepción". Usado sabiamente, beneficiará nuestro trabajo y puede mejorar significativamente la calidad del código que escribimos.
Nicrosoft ([email protected]) 2001.7.25
Fuente original: Documento Sunistudio (http://www.sunistudio.com/asp/sunidoc.asp)