Embarcadero Delphi
Uso di try, tranne, e infine
Ricerca…
Sintassi
Prova-eccetto: prova [istruzioni] tranne [[[su E: ExceptionType do statement]] [else statement] | [dichiarazioni] fine;
Try-finally: prova [statement] finally [statement] end;
Prova semplice .. esempio finale per evitare perdite di memoria
Utilizzare try
- finally
per evitare perdite di risorse (come la memoria) nel caso in cui si verifichi un'eccezione durante l'esecuzione.
La procedura seguente salva una stringa in un file e impedisce a TStringList
di fuoriuscire.
procedure SaveStringToFile(const aFilename: TFilename; const aString: string);
var
SL: TStringList;
begin
SL := TStringList.Create; // call outside the try
try
SL.Text := aString;
SL.SaveToFile(aFilename);
finally
SL.Free // will be called no matter what happens above
end;
end;
Indipendentemente dal fatto che si verifichi un'eccezione durante il salvataggio del file, SL
verrà liberata. Qualsiasi eccezione andrà al chiamante.
Ritorno sicuro di un nuovo oggetto
Quando una funzione restituisce un oggetto (invece di usarne uno che è passato dal chiamante), fai attenzione che un'eccezione non provochi la perdita dell'oggetto.
function MakeStrings: TStrings;
begin
// Create a new object before entering the try-block.
Result := TStringList.Create;
try
// Execute code that uses the new object and prepares it for the caller.
Result.Add('One');
MightThrow;
except
// If execution reaches this point, then an exception has occurred. We cannot
// know how to handle all possible exceptions, so we merely clean up the resources
// allocated by this function and then re-raise the exception so the caller can
// choose what to do with it.
Result.Free;
raise;
end;
// If execution reaches this point, then no exception has occurred, so the
// function will return Result normally.
end;
I programmatori ingenui potrebbero tentare di catturare tutti i tipi di eccezione e restituire nil
da tale funzione, ma questo è solo un caso speciale della pratica scoraggiata generale di catturare tutti i tipi di eccezione senza gestirli.
Prova finalmente nidificata dentro prova - eccetto
Un blocco try
- finally
può essere annidato all'interno di un try
- except
blocco.
try
AcquireResources;
try
UseResource;
finally
ReleaseResource;
end;
except
on E: EResourceUsageError do begin
HandleResourceErrors;
end;
end;
Se si verifica un'eccezione all'interno di UseResource
, l'esecuzione passerà a ReleaseResource
. Se l'eccezione è EResourceUsageError
, l'esecuzione salterà al gestore delle eccezioni e chiamerà HandleResourceErrors
. Eccezioni di qualsiasi altro tipo salteranno il gestore di eccezioni sopra e salveranno al prossimo try
- except
blocco dello stack di chiamate.
Le eccezioni in AcquireResource
o ReleaseResource
causeranno l'esecuzione al gestore delle eccezioni, saltando il blocco finally
, perché il blocco try
corrispondente non è ancora stato immesso o perché il blocco finally
è già stato immesso.
Prova - eccetto nidificata dentro prova-finalmente
Un try
- except
blocco può essere annidato all'interno di un blocco try
- finally
.
AcquireResource;
try
UseResource1;
try
UseResource2;
except
on E: EResourceUsageError do begin
HandleResourceErrors;
end;
end;
UseResource3;
finally
ReleaseResource;
end;
Se si verifica un EResourceUsageError
UseResource2
in UseResource2
, l'esecuzione salterà al gestore delle eccezioni e chiamerà HandleResourceError
. L'eccezione verrà considerata gestita, quindi l'esecuzione continuerà a UseResource3
e quindi ReleaseResource
.
Se un'eccezione di qualsiasi altro tipo si verifica in UseResource2
, lo show del gestore di eccezioni qui non verrà applicato, quindi l'esecuzione salterà sulla chiamata UseResource3
e passerà direttamente al blocco finally
, dove verrà chiamato ReleaseResource
. Successivamente, l'esecuzione salterà al successivo gestore di eccezioni applicabile mentre l'eccezione riempie lo stack di chiamate.
Se si verifica un'eccezione in qualsiasi altra chiamata nell'esempio precedente, HandleResourceErrors
non verrà chiamato. Questo perché nessuna delle altre chiamate si verifica all'interno del blocco try
corrispondente a quel gestore di eccezioni.
Prova infine con 2 o più oggetti
Object1 := nil;
Object2 := nil;
try
Object1 := TMyObject.Create;
Object2 := TMyObject.Create;
finally
Object1.Free;
Object2.Free;
end;
Se non si inizializzano gli oggetti con nil
all'esterno del blocco try-finally
, se uno di essi non viene creato verrà eseguito un AV sul blocco finally, poiché l'oggetto non sarà nullo (poiché non è stato inizializzato) e causerà un'eccezione
Il metodo Free
verifica se l'oggetto è nullo, quindi l'inizializzazione di entrambi gli oggetti con nil
evita errori durante la loro liberazione se non sono stati creati.