Home

Delphi exception handling (afhandelen van uitzonderingen)

Inleiding

Delphi beschikt over een geavanceerd fouten afhandelingssysteem.
In dit paper kijken we hoe e.e.a. geimplementeerd kan worden binnen je applicatie.

Foutenafhandeling binnen Delphi

Het systeem van foutenafhandeling binnen Delphi heeft als voordeel dat programma's ondanks eventuele
fouten toch kunnen blijven draaien zonder dat het programma crasht.
Het programma kan netjes afsluiten, zodat gegevens opgeslagen kunnen worden.

Wanneer er tijdens de uitvoer van een programma iets fout gaat zal Delphi een uitzondering genereren.
Deze uitzondering kan in de betreffende code opgelost worden. (Je moet dit wel zelf programmeren uiteraard)
Als de programmacode niets doet zal de fout doorgespeeld  worden aan de aanroepende code, net zolang totdat
er code is die de fout oplost. Als laatste, als er geen code is die de fout oplost, zal Delphi zelf de fout melden en trachten
deze op te lossen op een nette manier.
De fout komt als het ware uit het programma omhoog 'drijven'.

Het systeem

De volgende sleutelwoorden behoren tot het foutafhandelingssysteem :

try
except
finally
raise

try
geeft het begin van de code aan waar op gechecked wordt.
except geeft het einde van de deze code aan.
finally geeft code aan die ondanks de fout absoluut uitgevoerd moet worden.
raise geeft de mogelijkheid om zelf een fout te genereren.

Bovenstaande sleutelwoorden worden in twee soorten blokken gebruikt :

Het try......except blok :

try
  // de code
except
  on exception do // los het hier op en meld het op een nette manier aan de gebruiker
end;

Wanneer de code in het try gedeelte geen runtime error genereert zal de code in het
except gedeelte overgeslagen worden.
Loopt de code tegen een runtime error op dan zal het programma verder gaan met het except gedeelte.
Daar kan de fout achterhaalt worden door te toetsen welke exception het betreft, en zonodig worden hersteld.
De gebruiker zal de door Delphi gegenereerde exception nooit zien.
Kortom het except gedeelte staat een 'nette' oplossing van de fout toe met een 'vriendelijke' foutmelding naar de gebruiker.
In het volgende stukje code wordt een deling door nul afgevangen :

function DoDivide (x,y : integer) : Double;
begin
  try
    Result : x / y;
  except //Except blok
    on EZeroDivide do //Indien deze fout dan oplossen!
    begin
      Result := 0,0;
      ShowMessage('Deling door nul!');
    end;
  end;
end;


Het try... finally blok :

try
  // de code
finally
   //Voer uit te voeren code uit, wat er ook gebeurd!
end;

Dit blok garandeert dat de code na finally hoe dan ook uitgevoerd wordt.
Dit blok is vooral belangrijk ten aanzien van het free-en van objecten. (Resource protection) Door objecten bijv. forms  in het
finally gedeelte te free-en wordt voorkomen dat zij onnodig resources gebruiken.
In onderstaand voorbeeld wordt dynamisch een form gecreëerd binnen een Try..finally block.

procedure TForm1.button1Click(Sender : TObject);
begin
  frmShowResult := TfrmShowResult.Create(self);
  try //Finally blok
    frmShowResult.ShowModal;
  Finally
    frmShowResult.free;//Free the form
  end;
end;

Raise exceptions

Raise kan gebruikt worden om de exception te re-raisen. Hiermee kan de exception alsnog afgehandeld worden.
Tevens kan je met raise zelf exceptions genereren : raise EDiveByZero.Create ('Deling door nul');

Beide blokken nesten

Beide blokken kunnen genest gebruikt worden.
Onderstaande code is een procedure die de getallen uit twee editboxen van elkaar aftrekt.
De uitkomst mag niet kleiner dan nul zijn, indien de uitkomst kleiner dan nul is moet de uitkomst nul worden.
Omdat tijdens de uitvoer van de functie de cursor wordt verandert in een zandloper dient naast het except blok
een finally blok genest worden. Dit om er voor te zorgen dat de cursor weer normaal wordt, ondanks een optredende fout.
Merk op dat door gebruik te maken van het object E alle soorten fouten afgehandeld kunnen worden.
E is een object van het type exception en ontvangt de waarde van het gecreëerde exception object.
Dus ook als er in de edit's letters worden ingevoerd zal onderstaande code dit netjes afhandelen.

function TForm1.DoeBerekening : Integer;
begin
  Try //Finally blok
    Try //Except blok
      result := StrToInt(Edit1.text) - StrToInt(Edit2.text);
      if result < 0 then //raise 
        raise exception.Create('Uitkomst < 0');
    except               
      on E:exception do  //E is object van type exception
      begin 
        result := 0;
        showmessage(E.Message);
      end;
    end;
  Finally
    Screen.Cursor := crDefault; //Hoe dan ook cursor 'resetten'
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Screen.Cursor := crHourGlass;
  lblUitkomst.caption := IntToStr(Doeberekening);
end;

Het maken van eigen exceptions

Exceptions zijn eenvoudig zelf te maken :
type
  EMijnFout = class ( Exception );

raise EMijnFout.Create ('Sorry mijn fout!'):

Einde exceptions.

arrows.gif (215 bytes)Top