Něco o exceptions

vložil Radek Červinka 10. dubna 2011 23:49

Koncept výjimek v Delphi je dobře vymyšlen a dokonce jsem kdesi četl, že je částečně patentován, jelikož v době Delphi 1 byl naprosto převratný způsobem zpracování za běhu (nějak to souviselo s efektivním odvíjením zásobníku při výjimce, detaily si nepamatuji a snad se nepletu).

Mimochodem Windows podporují výjimky až od 32bit verzí, tj. Delphi 1, které bylo 16bit mělo výjimky vlastní a až Delphi 2 mapují část výjimek na výjimky Windows.

Od Delphi 1 je základem třída Exception, která byla v Delphi 2009 trochu rozšířena - přece jen je to už pár let.

Pro začátečníky je stručné pojednání o výjimkách v článku pro začátečníky (pravý sloupec), pro ty ostatní: třída byla rozšířena o objekt InnerException a podporu pro StackTrace. Dám sem rovnou ukázku kódu, na formuláři jsou dvě tlačítka a jejich obsluhy.

    1unit Unit1;
    2
    3interface
    4
    5uses
    6  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    7  Dialogs, StdCtrls;
    8
    9type
   10  TForm1 = class(TForm)
   11    btn1: TButton;
   12    btn2: TButton;
   13    procedure btn1Click(Sender: TObject);
   14    procedure btn2Click(Sender: TObject);
   15  private
   16    { Private declarations }
   17    procedure mTest;
   18    procedure mTest2;
   19  public
   20    { Public declarations }
   21    e:Exception;
   22  end;
   23
   24var
   25  Form1: TForm1;
   26
   27implementation
   28uses
   29 JclDebug; //jen pro výpis stacku
   30{$R *.dfm}
   31
   32procedure TForm1.btn1Click(Sender: TObject);
   33begin
   34  try
   35    mTest;
   36  except
   37    on E:Exception do
   38      ShowMessage(E.ToString);
   39  end;
   40end;
   41
   42procedure TForm1.btn2Click(Sender: TObject);
   43begin
   44  try
   45    mTest2;
   46  except
   47    on E:Exception do
   48    begin
   49      ShowMessage(E.ToString);
   50      if E.InnerException <> nil then
   51        ShowMessage(E.InnerException.Message);
   52      ShowMessage(E.StackTrace)
   53    end;
   54  end;
   55end;
   56
   57procedure TForm1.mTest;
   58var
   59  sl:TStringList;
   60begin
   61  try
   62    sl := TStringList.Create;
   63    try
   64      raise SysUtils.EProgrammerNotFound.Create('Tady to někdo neudělal dobře.');
   65
   66    finally
   67      sl.Free;
   68    end;
   69  except
   70    on E:Exception do
   71    begin
   72      E.Message := E.Message + #13#10 + 'Další řádek';
   73      raise;
   74    end;
   75  end;
   76end;
   77
   78type
   79  EOwnException =class(Exception);
   80
   81procedure TForm1.mTest2;
   82var
   83  sl:TStringList;
   84begin
   85  try
   86    sl := TStringList.Create;
   87    try
   88      raise SysUtils.EProgrammerNotFound.Create('Tady to někdo neudělal dobře.');
   89
   90    finally
   91      sl.Free;
   92    end;
   93  except
   94    on E:Exception do
   95    begin
   96      Exception.RaiseOuterException(EOwnException.Create('Nova exception'));
   97    end;
   98  end;
   99end;
  100
  101// podpora pro výpis stacktrace via JCL
  102
  103//http://www.sql.ru/forum/actualthread.aspx?tid=641304&hl=stacktrace
  104function GetExceptionStackInfoProc(P: PExceptionRecord):Pointer;
  105begin
  106  Result := TJclStackInfoList.Create(False, 0, nil);
  107end;
  108
  109function GetStackInfoStringProc(Info: Pointer):String;
  110var
  111  Stack:TJclStackInfoList;
  112  Str:TStringList;
  113begin
  114  if Info = nil then Exit;
  115  str := nil;
  116 try
  117  str := TStringList.Create;
  118  Stack := TJclStackInfoList(Info);
  119  Stack.AddToStrings(Str);
  120  Result :=  Str.Text;
  121 finally
  122    FreeAndNil(Str);
  123 end;
  124
  125end;
  126
  127procedure CleanUpStackInfoProc(Info: Pointer);
  128begin
  129  FreeAndNil(TJclStackInfoList(Info));
  130end;
  131
  132initialization
  133  Exception.CleanUpStackInfoProc := CleanUpStackInfoProc;
  134  Exception.GetExceptionStackInfoProc := GetExceptionStackInfoProc;
  135  Exception.GetStackInfoStringProc :=   GetStackInfoStringProc;
  136end.

mTest a mTest2 jsou dvě ukázky jak při odchycení výjimky modifikovat výjimku. mTest bude fungovat i v Delphi před 2009, druhý způsob používá InnerException, kdy

Exception.RaiseOuterException(EOwnException.Create('Nova exception'));

vyvolá novou výjimku a právě zpracovávaná je přesunutá do InnerException. To samozřejmě lze opakovat a tak jde přes InnerException vybudovat řetěz výjimek (normálně by byla jen dostupná historie volání, ale všechny další informace pak musí být součástí jedné výjimky podobně jako v předchozím případě).

Metoda ToString pak samozřejmě prochází všechny dostupné InnerException.

Druhá nová věc je možnost výpisu zásobníku. Exception nyní obsahuje property StackTrace, která volá rutinu pro získání zásobníku, která se nastavuje přes

 Exception = class(TObject)
….
  class var
    GetExceptionStackInfoProc: function (P: PExceptionRecord): Pointer;
    GetStackInfoStringProc: function (Info: Pointer): string;
    CleanUpStackInfoProc: procedure (Info: Pointer);
    class procedure RaiseOuterException(E: Exception); static;
 end; 

viz sekce initialization v příkladu.

Uvedené zjišťování používá klasické trasování volání bez použití InnerException z JCL.


Nabízíme Delphi školení na různá témata, primárně ve Vaší firmě.

Tagy: , , ,

Novinky v Delphi

Komentování ukončeno

Naše nabídka

Partial English version.

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy nebo burzy práce).

Pokud chcete podpořit tento server libovolnou částkou, můžete použít PayPal. Moc děkuji.

Delphi Certified Developer

O Delphi.cz

Delphi je jediný moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64 , Mac OSX a na iPhone a Android (s výhledem na další platformy díky FireMonkey) na současném trhu (včetně Windows 8.1).

V současnosti je světová komunita přes dva miliónů vývojářů.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Anketa

Poslední komentáře

Comment RSS