bug_report Programmazione

Gestire le eccezioni in Delphi: try/except/finally e buone pratiche

calendar_today personTeam EGSOFT schedule5 min di lettura

Due blocchi diversi per due scopi diversi

Delphi offre due varianti del blocco di gestione eccezioni, spesso confuse da chi inizia: try...except intercetta un'eccezione e permette di reagire (mostrare un messaggio, registrare un log, tentare un recupero), mentre try...finally garantisce che un blocco di codice venga eseguito comunque, che si sia verificata un'eccezione o meno — tipicamente per rilasciare risorse come file aperti, connessioni al database o oggetti creati dinamicamente. I due blocchi rispondono a domande diverse: "cosa faccio se qualcosa va storto?" per except, "cosa devo comunque eseguire alla fine, in ogni caso?" per finally.

Il pattern più comune: create/try/finally/free

Per qualsiasi oggetto creato dinamicamente con Create, il pattern raccomandato in Delphi è creare l'oggetto prima del blocco try, e liberarlo in un blocco finally subito dopo: Obj := TMyClass.Create; try ... finally Obj.Free; end;. In questo modo, anche se il codice all'interno del try solleva un'eccezione, l'oggetto viene comunque liberato correttamente, evitando memory leak. Creare l'oggetto dentro il blocco try, prima della clausola finally, è un errore diffuso: se il costruttore stesso solleva un'eccezione, il finally tenterebbe comunque di liberare un riferimento non ancora assegnato.

Catturare l'eccezione giusta, non tutte

Un except generico che intercetta Exception (la classe base di tutte le eccezioni) nasconde qualsiasi errore, incluso quelli inattesi che invece dovrebbero interrompere l'esecuzione e segnalare un bug. È preferibile intercettare tipi di eccezione specifici — on E: EConvertError do, on E: EDatabaseError do — gestendo solo i casi che ci si aspetta davvero possano verificarsi, e lasciando propagare (o rilanciando con raise) tutto il resto.

Creare eccezioni personalizzate

Per errori specifici della propria applicazione, è buona pratica derivare una nuova classe da Exception (ad esempio ESaldoInsufficiente = class(Exception)), da sollevare con raise ESaldoInsufficiente.Create('Saldo insufficiente per completare l'operazione'). Questo permette al codice chiamante di distinguere tra un errore di business specifico e un errore generico di sistema, gestendoli in modo diverso quando serve.

L'errore da evitare: except senza except

Un blocco try...except end; vuoto, che intercetta silenziosamente qualsiasi eccezione senza fare nulla, è probabilmente l'errore più pericoloso in assoluto: nasconde ogni problema, rendendo il debug quasi impossibile quando qualcosa smette di funzionare senza un motivo apparente. Se davvero un'eccezione va ignorata (un caso raro), è preferibile farlo esplicitamente e con un commento che ne spieghi il motivo, non per abitudine.

bug_reportAltri articoli su Programmazione grid_viewTutti gli articoli
Scrivici su WhatsApp