2010-11-11 10 views
15

En Delphi, ¿cómo se puede usar try, finally y catch together? Un Java/C# equivalente sería algo como:C#/Java "Try/Finally/Catch" construcción equivalente en Delphi

try { 
    // Open DB connection, start transaction 
} catch (Exception e) { 
    // Roll back DB transaction 
} finally { 
    // Close DB connection, commit transaction 
} 

Si intenta esto en Delphi, También se puede usar try/finally o tratar/excepción; pero nunca los tres juntos. Me gustaría código como el siguiente (que no compila):

try 
    // Open DB connection, start transaction 
except on e: Exception do 
begin 
    // Roll back transaction 
end 
finally // Compiler error: expected "END" not "finally" 
begin 
    // Commit transaction 
end 
+0

Porque 'finally' y' except' son semánticamente totalmente diferentes, en Delphi no pueden estar en la misma declaración. Basta con mirar las fuentes RTL/VCL donde 'finally' y' except' se usan (y su proporción). Apenas verá los lugares donde están cerca. –

+4

No ponga "commit transaction" en un bloque 'finally'. Si se produce una excepción, no desea confirmar nada. En especial, no desea intentar comprometer una transacción que ya realizó en el bloque 'except' anterior. Commit debe ser la acción final en la sección 'try'. –

Respuesta

18

En Delphi se puede utilizar el siguiente patrón:

// initialize/allocate resource (create objects etc.) 
... 
try 
    try 
    // use resource 
    ... 
    except 
    // handle exception 
    ... 
    end; 
finally 
    // free resource/cleanup 
    ... 
end 
+0

Brillante. Me gusta cómo el anidamiento imita la legibilidad esperada de try, catch, finally (como estoy acostumbrado desde Java/C#). – ashes999

+0

Lo aprendí por primera vez en Java y lo "porté" a Delphi;) – mjn

+2

Excepto que agrega un nivel de indentación innecesario. Realmente me gustaría que hicieran posible escribir try ... por fin ... excepto ... fin, incluso mejor si está en orden aleatorio (dependiendo de lo que se procesa primero), y aún mejor si sería posible hacer "try ... excepto A ... por fin ... excepto B ... fin ". Realmente no es tanto en términos de codificación, y no afecta el lenguaje, pero agrega un toque agradable. – himself

9

escritura

try 
    // allocate resource here 
    try 
    finally 
    // free resource here 
    end; 
except 
    // handle exception here 
end; 
+2

Igualmente funcional como la respuesta de mjustin, pero me gusta más, hace que sea más legible que la excepción se detecta primero y luego el bloque final llega al final. O tal vez estoy parcial, ya que ese es el estilo Java/C# :) – ashes999

+5

La respuesta de mjustin no detecta excepciones en el destructor. Este es un mejor enfoque. – gabr

+3

Eso no importa, @Gabr. Si un destructor arroja excepciones, ya estás condenado. No hay absolutamente nada que su programa pueda hacer para solucionar el problema que causó un error como ese. –

4

Mientras que la anidación del try...except Dentro de un try...finally (o viceversa) responde directamente a la pregunta, me gustaría señalar que la pregunta original, independientemente del idioma que esté usando, está mezclando las preocupaciones del error. manejo y manejo de recursos. Try...except y try...finally son feos. Te distraen de lo que hace tu código. Un mejor enfoque es extraer el control de errores en un método separado:

procedure Read(Connection: TDBConnection); 
begin 
    try 
    //Read DB 
    except 
    //Handle Exception 
    end; 
end; 

procedure ReadRecord; 
begin 
    DBConnection.Open; 
    Read(DBConnection); 
    DBConnection.Close; 
end; 

Ahora su gestión de errores es autónomo y puede ser ignorada para que pueda concentrar su atención en el camino feliz.

¡Espera! ¿Qué pasa con el open y el close? ¿Qué pasa si generan excepciones?

Simple. Envuelva esas operaciones en el intento ... excepto las funciones y trátelas también. No debería ser necesario. Si la biblioteca de DB que utiliza vale algo, una excepción en un open o close no dejará la conexión en un estado desconocido. Por otra parte, las excepciones están ahí para las cosas que no espera.

La misma técnica se puede utilizar con cualquier recurso: creación de objetos, acceso a archivos, etc. Cuando se garantiza que el cuerpo de su función no genera una excepción, no es necesario try...finally.

Por supuesto, hay una sobrecarga de llamada de función, pero en la mayoría de los casos es insignificante y las funciones de manejo de errores deben ser lo suficientemente pequeñas como para permitir que el compilador las alinee.

+0

+1 para ir más allá de la pregunta obvia. Lamentablemente, mi pregunta es puramente sintáctica, no semántica. – ashes999

Cuestiones relacionadas