在尝试除块之前,在Delphi Application.OnException中捕获异常

And*_*res 0 delphi try-catch onexception

我想记录delphi应用程序中引发的每个异常.为此,我在项目源代码中用我自己的一个覆盖了Application.OnException事件.

program Project;

uses
  Vcl.Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Logger in 'Logger.pas',
  JCLDebugHandler in 'JCLDebugHandler.pas';

{$R *.res}

begin
   Application.Initialize;
   Application.OnException := TApplicationException.AppException;
   Application.MainFormOnTaskbar := True;
   Application.CreateForm(TForm1, Form1);
   Application.Run;
end.
Run Code Online (Sandbox Code Playgroud)

这很好用,但我没有抓住这个解决方案,在try-except块中捕获了异常.

当在except块中捕获异常时,它不会触发Application.OnException事件.

有没有办法首先在Application.OnException事件而不是except块中捕获它?

Del*_*ics 6

Application.OnException处理器只要求未处理的异常.

未处理的异常是指没有try..except块已捕获异常或已捕获然后重新引发的异常.

使用一些简单的示例来演示,让我们假设这实际上是应用程序中唯一的代码,并且没有其他异常处理程序......

try
  a := 42 / 0;
except
  on EDivisionByZero do
  begin
    Log.i('Silly division by zero error has been logged');
    raise;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,会捕获异常,但应用程序没有处理异常的策略,因此只需记录已发生的异常,然后重新引发异常.执行将在任何外部except块中继续.如果没有,或者任何可能存在的也会重新引发异常,那么最终异常将到达Application.OnException处理程序.

但是异常处理程序可能不需要重新引发异常:

try
  a := 42 / 0;
except
  on EDivisionByZero do
    a := 0;
end;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,异常处理程序处理除以零,并且不会重新提升它,因为代码很乐意在这种情况下继续使用零结果(不太可能,但这只是一个例子).

由于不重新引发异常,因此执行继续执行(在try..except块之后),就好像异常从未发生过一样.你Application.OnException永远不会知道它.

总结: Application.OnException是你处理未处理异常的最后机会.这不是第一次回应任何例外的机会.

在任何应用程序代码有机会作出反应或处理它们之前,在它们发生时拦截异常可能的,但这是非常先进的东西,并且没有提供"开箱即用"的简单机制.

幸运的是,您可以使用第三方库,这些库可能会提供您要在应用程序中引入的功能.

您可能希望查看Delphi的流行版本是madExcept.