沉默的异常 EAbort

    技术2022-05-11  61

    1.         什么是沉默的异常?(为什么不是沉默的羔羊?;-))

    沉默的异常,即Slient Exceptions,指的是在缺省情况下不会出现讨厌的消息提示框的异常类型:EAbort。在Object Pascal中,异常类EAbort是所有沉默的异常类的祖先类(而EAbort是继承Exception而来)。引发(Raise)一个EAbort将导致一个执行模块的停止,直到有最外层的异常处理模块截获它,但是并不因此出现带有红色停止标志的消息框。参考如下代码:

          try

            ShowMessage('Hello1');

            Raise EAbort.Create('Abort it');

            ShowMessage('Hello2');

         except

           on E: Exception do

             showmessage('On Exception');

         end;

     

           执行结果显示两个消息框,一个是”Hello1”,另一个是”On Exception”。这表明,EAbort确实发挥了作用,因为它跳过了”ShowMessage(‘Hello2’)”这个语句;同时,没有出现”Abort it”的消息框,也证实了EAbort异常类的不出现对话框的特点(在设计期间也是如此);并且,消息框”On Exception”表明,虽然可能EAbort是个不同于普通异常的异数,但这并不妨碍我们沿用老的Try-Except语句来捕获它。

     

    2.         为什么要用EAbort

    EAbort在某些场合下很有用。比如当我们需要终止某项操作,而又不希望让用户察觉(不想让他们看到默认的异常消息框)。当然,要达到相同的效果,使用普通的异常也可以做到(比如使用Try-Except句型,将代码放在Try段,需要终止操作则raise一个异常,而在Except段不写任何代码),但是这一切没有比使用EAbort来的简单又直接。

     

    3.         有什么简便一点的吗?――使用Abort过程

    SysUtils单元中定义的一个过程Abort可以让我们方便的使用EAbort。查看Abort的实现源码:

     

        procedure Abort;

          function ReturnAddr: Pointer;

          asm

             MOV     EAX,[EBP + 4]

          end;

        begin

          raise EAbort.Create(SOperationAborted) at ReturnAddr;

        end;

           这里的SOperationAborted通常就是” Operation aborted”

     

    4.         揭开面纱――实现原理

    也许各位和我一样,对于EAbort为什么是沉默的感到好奇。Delphi在其内部,究竟对EAbort做了什么手脚呢?让我们一起来看个究竟。

           打开一个新的工程,点击Find in Files,输入”EAbort”关键字,然后选中Search in Directories单选框,并将Search Directory Options中的File Mask编辑框设置为Delphi源码所在的目录名(比如我的是:D:Program FilesBorlandDelphi6Source),同时别忘记给Include SubDirectory打勾。最后,点击”OK”开始搜索。

           结果我们发现Delphi源码中与EAbort有瓜葛的达17处之多。除去Sysutils单元中两处对EAbort的声明以及部分注释语句,我们发现绝大多数代码类似于:

           if ExceptObject is EAbort then

           以及:

           if not (E is EAbort) then

           等等。

           无一不是根据RTTI来对EAbort特殊对待的――原来EAbort的实现就这么简单!

           值得关注的两个单元是:Forms(Linux版本为QForms)AppEvnts,在前者的代码中我们更不难找到问题的答案。参见Delphi源码:

        procedure TApplication.HandleException(Sender: TObject);

        begin

          if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);

          if ExceptObject is Exception then

          begin

            if not (ExceptObject is EAbort) then

              if Assigned(FOnException) then

                FOnException(Sender, Exception(ExceptObject))

              else

                ShowException(Exception(ExceptObject));

          end else

            SysUtils.ShowException(ExceptObject, ExceptAddr);

        end;

     

    5.         AbortBreakExit之区别

    AbortBreakExit有些相似,又很不同。Break用来在循环语句中跳出一层循环。Exit用来跳出当前执行的函数体(或过程体)。Abort可以让你跳出一层或者多层代码段,直到有异常捕获的代码将它捕获。

    例如:try  (1) //执行了  abort;   (2) //不执行exception  (3) //执行了end; 用 Abort 能够执行 exception 里边的代码,但是如果用 Exit,就直接离开,不管 exception。

    例如: procedure p1;begin  p2;  p3;end;procedure p2;begin  abort; //exit;end;procedure p3;begin  //showmessage()..end;

    如果用 Abort,则执行不到 P3,如果用 Exit 就能够执行到 P3。

     

    6.         自定义沉默的异常

    与声明一个普通异常类的子类相同,只需将EAbort及其子类作为祖先类即可:

    TMyException = Class(EAbort);

    TNextException = Class(EAbort);

    等等。

     

    最新回复(0)