Gli errori in Delphi vengono gestiti attraverso le eccezioni. Quando si verifica un
errore in fase di esecuzione, viene sollevata un'eccezione. Un eccezione non è altro che
un oggetto che contiene informazioni sull'errore (come per esempio il messaggio di errore)
che vengono passate ad un gestore di eccezioni. Ciò permette di distinguere la
logica di esecuzione del codice da quella che gestisce gli errori. Ogni volta che si
utilizza la unit SysUtils, tutti gli errori di runtime vengono trasformati
automaticamente in eccezioni. Esistono in Delphi diverse classi di eccezioni predefinite,
ma è anche possibile definirne di nuove.
La dichiarazione di una eccezione è uguale alla dichiarazione di un normale classe. In
genere tutte le eccezioni derivano dalla classe Exception definita nella unit SysUtils.
Come per una normale classe, è possibile raggruppare le eccezioni utilizzando
l'ereditarietà. Le seguenti dichiarazioni sono prese dalla unit SysUtils
Type EMathError = Class(Exception)
EInvalidOp = Class(EMathError);
EZeroDivide = Class(EMathError);
Proprio come in una normale classe, all'interno della dichiarazione di una eccezione
possono essere dichiarati dei campi che possono contenere informazioni addizionali
sull'errore come per esempio il codice dell'errore.
Type EInOutError = Class(Exception)
ErrorCode : Integer;
End;
Per creare un oggetto eccezione occorre utilizzare la seguente sintassi
Raise Oggetto at Indirizzo
oppure
Raise Oggetto.Create at Indirizzo
All'interno dell'istruzione raise occorre secificare un oggetto
eccezione oppure chiamare il costruttore della classe eccezione. Il parametro Indirizzo
può contenere un puntuntatore ad una procedura o funzione, utile per sollevare
l'eccezione dal punto dello stack precedente a quello in cui si è verificata l'eccezione.
Sia il parametro Oggetto che Indirizzo sono facoltativi. Se non viene
indicato nessun parametro dopo l'istruzione raise si avrà come risultato
la rigenerazione dell'eccezione attiva. Quando viene sollevata un'eccezione tramite
l'istruzione raise il controllo dell'esecuzione viene trasferito al
gestore di eccezioni, ricercandolo partendo dal gestore più interno alla classe data (ad
esempio un blocco try...Except). Le eccezioni generate
vengono automaticamente distrutte dopo essere state gestite; quindi non si deve mai
eliminare manualmente l'eccezione creata.
try...Except
L'istruzione try...Except permette di definire un gestore
di eccezioni. Il formato dell'istruzione è
try
Codice
Except
GestioneEccezioni
End;
In pratica il codice eseguito tra le parole try ed Except
è protetto dal sollevamento delle eccezioni. Qualora un'eccezione fosse sollevata
all'interno del codice Codice il controllo dell'esecuzione viene passato al
codice rappresentato da GestioneEccezioni.
Il blocco GestioneEccezioni può essere composto da una sequenza di istruzioni
o da una sequenza di gestori di eccezioni. Per definire un gestore di eccezione per una
certa eccezione, occorre utilizzare la seguente sintassi
On Identificatore : TipoClasseEccezione do Codice
Identificatore è facoltativo e permette di definire un riferimento
all'oggetto eccezione che è valido solamente per il codice contenuto nel blocco Codice.
TipoClasseEccezione indica invece il tipo della classe a cui corrisponde
l'eccezione da gestire.
Codice è il blocco di codice che viene eseguito se il tipo dell'eccezione
sollevata corrisponde al tipo indicato in TipoClasseEccezione o ne è un
antenato.
Facoltativamente può essere definito dopo l'elenco dei gestori di eccezione un blocco else
che gestica tutte le eccezioni non gestite dai gestori definiti.
Ovviamente, se non si verisicano eccezioni durante l'esecuzione del codice Codice
l'esecuzione prosegue fino all'istruzione precedente la parola except e
quindi salta all'istruzione immediatamente successiva alla parola chiave end.
Ecco due esempi che raccolgono ciò che abbiamo visto
try
...
Except
On EZeroDivide do GestisciZeroDivideException;
On EOverFlow do GestisciOverFlowException;
On EMathError do GestisciMathErrorException;
Else
GestisciTutteLeAltreEccezioni;
End;
try
...
Except
GestisciLeEccezioni;
End;
try...Finally
Il blocco try...Finally assicura che una determinata
sequenza di codice venga eseguita indifferentemente dal fatto che sia stata sollevata
un'eccezione o no. Per esempio è utile in alcuni casi assicurarsi di liberare le risorse
occupate in ogni caso. La sintassi è simile a quella di try..Except
try
Codice
Finally
CodiceDaEseguireComunque
End;
L'esecuzione del codice procede dalla prima istruzione del blocco di codice Codice.
Se si verificano eccezioni, l'esecuzione del codice Codice viene interrotta e
riprende con la prima istruzione contenuta nel blocco CodiceDaEseguireComunque.
Al termine dell'esecuzione del codice CodiceDaEseguireComunque, l'eccezione viene
sollevata di nuovo.
Se non si verifica alcuna eccezione, l'esecuzione procede fino all'ultima istruzione
nel codice Codice e prosegue con l'esecuzione del codice contenuto nel blocco CodiceDaEseguireComunque.