结构化异常处理
我想指出,您的异常处理方法是非常乏味和浪费的编码。更不用说相当危险了。当有更实用的方法时,您不希望在代码中使用单独的处理程序来记录异常。
幸运的是,Delphi 提供了使这更容易的方法。首先是关于结构化异常处理的一些背景知识......大多数开发人员都会错误地通过编写如下代码来尝试处理错误:
try
//Do Something
except
//Show Error
//Log Error
end;
上述代码的问题在于它吞下了错误。即使用户看到错误消息,错误本身也对程序的其余部分隐藏。这可能会导致程序的其他部分因为错误而做他们不应该做的事情。
想象一个调用以下例程的程序:LoadAccount; ApplyDiscount; ProcessPayment;。但是第一个例程会引发错误。程序员(错误地认为他们很勤奋)决定如上所述“处理”。 问题是接下来的两个例程仍将被调用好像没有任何问题!这可能意味着对错误帐户应用了折扣并处理了付款!
关键是结构化异常处理使我们免于这些麻烦(只要我们不破坏它的工作方式)。如果LoadAccount 例程没有尝试“处理”异常,那么当应用程序处于“异常状态”时,代码将简单地跳出例程,直到找到 finally / 除了处理程序。
这非常适合事件驱动程序。
假设用户单击了一个按钮,该按钮将导致您的程序启动一个多步骤任务:使用循环、调用子方法、创建对象等。如果 任何事情 出错,您想放弃整个任务并等待下一个输入。你不想固执地继续尝试完成任务;因为您要么会遇到更多错误,要么更糟:以后的更改会做错事,因为之前的必要步骤没有成功完成。
轻松记录错误
如前所述,如果您只是不理会异常,错误将“冒泡”到外部异常处理程序。在标准的 GUI 应用程序中,这将是默认的 Application 异常处理程序。
其实在这个阶段,没什么特别的:如果在前面描述的按钮点击任务的中间引发异常,默认的异常处理程序将显示一个给用户的错误信息。唯一缺少的是日志记录。幸运的是,Delphi 使您可以轻松拦截默认的Application 异常处理程序。因此,您可以提供自己的实现,并根据需要记录错误。
您需要做的就是:
- 使用
TExceptionEvent 签名编写一个方法。
例如。 procedure MyHandleException(ASender: TObject; E: Exception);.
- 然后使用:
Application.OnException := MyHandleException; 分配您的自定义处理程序
常规日志记录
当然,这仅涵盖异常记录。如果您想进行任何其他临时日志记录,您希望能够重用代码。这基本上要求您将日志记录代码移动到一个单独的单元中,所有其他单元可以根据需要调用。
所以把这些东西放在一起,你可能会做如下事情:
TLogger = class
public
procedure WriteToLog(S: string); //Performs actual logging of given string
procedure HandleException(ASender: TObject; E: Exception); //Calls WriteToLog
end;
那么你可以在你的程序单元中进行如下设置:
begin
Logger := TLogger.Create(...);
Application.OnException := Logger.HandleException;
Logger.WriteToLog('Custom exception handler has been assigned.');
//Rest of application startup code
end;
最后的想法
我提到如果发生意外的异常,你想放弃当前的任务。但是,如果您已经做了一些由于错误而现在应该撤消的事情,会发生什么。然后您只需按如下方式实现它:
try
//Do something
except
//Undo
raise; //NOTE: more often than not, one should re-raise an
//exception so that callers are aware of the error.
end;
请注意,this 是异常处理程序的主要用途。是的,它们也可以用来吞下异常。但他们应该仅在异常真正解决的情况下吞下异常。