2010-11-11 10 views
15

In Delphi, come si può provare, finalmente, e catturare insieme? A Java/C# equivalenti sarebbe simile:C#/Java "Try/Finally/Catch" costrutto equivalente in Delphi

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

Se provate questo a Delfi, è possibile utilizzare try/finally o provare/eccezione; ma mai tutti e tre insieme. Vorrei codice come il seguente (che non compilare):

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

Poiché 'finally' e' except' sono semanticamente totalmente diversi, in Delphi non possono essere nella stessa istruzione. Basta guardare le sorgenti RTL/VCL dove sono usati 'finally' e' except' (e il loro rapporto). Vedrai a malapena i posti dove sono vicini. –

+4

Non mettere "transazione di commit" in un blocco 'finally'. Se si verifica un'eccezione, non si desidera eseguire alcun commit. In particolare, non vuoi provare a eseguire il commit di una transazione che hai già eseguito il rollback nel precedente blocco 'except'. Commit dovrebbe essere l'azione finale nella sezione 'try'. –

risposta

18

In Delphi è possibile utilizzare il seguente schema:

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

Brillante. Mi piace come il nesting simuli la leggibilità attesa di try, catch, finally (come sono abituato da Java/C#). – ashes999

+0

L'ho imparato per la prima volta in Java e "trasferito" a Delphi;) – mjn

+2

Tranne che aggiunge un livello di indentazione inutile. Vorrei davvero che avrebbero reso possibile scrivere try..finally..except..end, ancora meglio se in ordine casuale (a seconda di cosa è stato elaborato per primo), e ancora meglio se fosse possibile fare "try" ..eccetto A..finalmente..eccetto B ... fine ". In realtà non è tanto in termini di codifica, e non appesantisce la lingua, ma aggiunge un tocco di classe. – himself

9

scrittura

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

Ugualmente funzionale come risposta di mjustin, ma mi piace di più - rende più leggibile che l'eccezione venga catturata per prima e poi il blocco finale arrivi alla fine. O forse sono solo di parte perché è lo stile Java/C# :) – ashes999

+5

La risposta di mjustin non rileva eccezioni nel distruttore. Questo è un approccio migliore. – gabr

+3

Questo non ha importanza, @Gabr. Se un distruttore lancia delle eccezioni, sei già condannato. Non c'è assolutamente nulla che il tuo programma possa fare per risolvere il problema che ha causato un errore del genere. –

4

Mentre nidificazione della try...except all'interno di un try...finally (o viceversa) risponde direttamente alla domanda Vorrei sottolineare che la domanda originale, indipendentemente dalla lingua utilizzata, mescola le preoccupazioni dell'errore gestione e gestione delle risorse. Try...except e try...finally sono brutti. Ti distraggono da ciò che sta facendo il tuo codice. Un approccio migliore è quello di estrarre la gestione degli errori in un metodo separato:

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

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

Ora la vostra gestione degli errori è a sé stante e può essere ignorato in modo da poter concentrare la vostra attenzione sul percorso felice.

Attendere! Che mi dici dello open e dello close? Cosa succede se sollevano eccezioni?

Semplice. Avvia quelle operazioni in prova ... eccetto le funzioni e gestiscile pure. Non dovrebbe essere necessario. Se la libreria DB utilizzata è valida, un'eccezione in uno open o close non lascerà la connessione in uno stato sconosciuto. Poi di nuovo, ci sono eccezioni per le cose che non ti aspetti.

La stessa tecnica può essere utilizzata con qualsiasi risorsa: creazione di oggetti, accesso ai file, ecc. Quando è garantito che il corpo della funzione non genera un'eccezione, try...finally non è necessario.

C'è, naturalmente, overhead di chiamata di funzione, ma nella maggior parte dei casi è trascurabile e le funzioni di gestione degli errori devono essere abbastanza piccole da consentire al compilatore di integrarle.

+0

+1 per andare oltre l'ovvia domanda. Sfortunatamente, la mia domanda è pura sintattica, non semantica. – ashes999