Delphi—it上的异常处理&x27;在它被引发后,它将创建自己的构造函数

Delphi—it上的异常处理&x27;在它被引发后,它将创建自己的构造函数,delphi,exception-handling,delphi-2006,Delphi,Exception Handling,Delphi 2006,问题是:在我引发一个异常之后,我能阻止它从它自己的构造函数传播吗?考虑下面的代码:< /P> unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TMyErrorClass = class(Exception) constructor Create(aMsg:String); end;

问题是:在我引发一个异常之后,我能阻止它从它自己的构造函数传播吗?考虑下面的代码:< /P>
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TMyErrorClass = class(Exception)
    constructor Create(aMsg:String);
  end;
  TForm2 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
begin
//
 raise TMyErrorClass.Create('test');
end;

{ TMyErrorClass}

constructor TMyErrorClass.Create(aMsg: String);
begin
 {$IFDEF DEBUG}
   Showmessage(aMsg);
 {$ELSE}
  //here I want to 'kill' the exception
 {$ENDIF}
end;

end.
调用raise后,如何在不添加try except/finally的情况下终止异常


LE:我有一个应用程序,它几乎有2000个这样的加薪…我正试图找到一个替代解决方案来为它编写错误处理…

阻止异常传播的方法是用一个
之外的
捕捉它。请注意,除了引发异常的
之外,您不会编写
,而是在希望它停止传播的位置编写

但是,您可能不应该阻止构造函数内部引发的异常在该构造函数外部传播。如果这样做,对象可能会部分构造

我相信,正如许多其他人所说,解决问题的正确方法是在遇到错误时引发异常,并让它们浮动到高级异常处理程序。

用于在应用程序的顶层实现通用异常处理行为。例如:

Application.OnException := MainForm.DefaultExceptionHandler;

procedure TMainForm.DefaultExceptionHandler (Sender : TObject; E : Exception);

begin
{$IfDef DEBUG}
ShowMessage (E.Message);
{$EndIf}
end;

在异常发生后继续正常控制流是个坏主意。

一旦您输入了
raise
语句,只有两种方法可以避免引发该异常:

  • 先提出别的东西。在即将引发的异常的构造函数中,可以首先创建并引发不同的异常。这将避免程序到达第一个
    raise
    语句

  • 终止线程,使其无法运行。您可以通过各种方式来实现这一点,包括
    ExitThread
    Halt
    、和
    ExitProcess
    ,它们在本文中几乎是等价的。您的程序将不再运行,但至少您已阻止它引发该异常


这两种方法都不能解决您试图解决的问题,但它们会满足您在问题中提出的要求。底线是,无论您试图做什么,在启动异常引发机制后平息异常都是错误的方法。您无法取消铃响,也无法取消异常。

当正在构造
TMyErrorClass
的实例时,它不知道是否将引发
。您要求打破一些基本的因果关系,比如语言异常处理。我永远不会把它放在生产代码中,因为它将是一颗滴答作响的定时炸弹。享受(用Delphi 6编写):

类型
TMyClass=类(TObject)
公众的
名称:字符串;
构造函数创建;
结束;
类型
REArguments=DWORD的数组[0..100];
前论证=^后论证;
类型
TRaiseExceptionProc=过程(dwExceptionCode,dwExceptionFlags,nNumberOfArguments:DWORD;lpArguments:PREArguments);stdcall;
变量
RaiseExceptionProc_Old:TRaiseExceptionProc;
过程MyRaiseException(dwExceptionCode、dwExceptionFlags、nNumberOfArguments:DWORD;lpArguments:PREArguments);stdcall;
变量
提出的对象:TObject;
开始
如果@RaiseExceptionProc_旧为零,则
开始
RaiseExceptionProc:=@RaiseExceptionProc\u Old;
RaiseExceptionProc_Old:=nil;
raiseObject:=指针(lpArguments^[1]);
如果RaiseObject是TMyClass,则
开始
提升对象自由度;
结束
其他的
开始
TRaiseExceptionProc(RaiseExceptionProc)(dwExceptionCode、dwExceptionFlags、nNumberOfArguments、lpArguments);
结束;
结束;
结束;
构造函数TMyClass.Create;
开始
继承;
名称:='MyClass';
RaiseExceptionProc_Old:=RaiseExceptionProc;
RaiseExceptionProc:=@MyRaiseException;
结束;
程序TForm1.按钮1单击(发送方:TObject);
开始
提高TMyClass.Create;
ShowMessage('不中断地继续');
结束;

我知道这对所有人来说都很难看,但我想与大家分享。代码不会修改异常类,这类似于全局异常处理程序,除非不会引发异常,否则将继续执行,就像什么都没有发生一样:

 
procedure TestException(dwExceptionCode, dwExceptionFlags,
    nNumberOfArguments: DWORD; lpArguments: PDWORD); stdcall;
var
  Arg: array of DWORD absolute lpArguments;
begin
{$IFDEF DEBUG}
  if (nNumberOfArguments > 1) and Assigned(lpArguments) and
      (TObject(Arg[1]).ClassName = TMyErrorClass.ClassName) then begin
    ShowMessage('Test');
    TObject(Arg[1]).Free;
    Exit;
  end;
{$ENDIF}
  windows.RaiseException(dwExceptionCode, dwExceptionFlags,
                            nNumberOfArguments, lpArguments);

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  RaiseExceptionProc := @TestException;
  ..

仅使用32位和D2007进行测试,我不知道它是否能正常工作。

如果你想在它建造之前就杀死它,为什么要首先将其提升?不要使用异常,只显示一个消息框。我有一个应用程序,它几乎有2000个这样的提升…我正试图找到一个替代的解决方案来为它编写错误处理..简单地回答这个问题-你不能这样做。这将使调试版本与发布版本完全不同,这当然不是正确的方法。只要给你的应用一个顶级异常处理程序来处理异常就行了。如果你的程序中有2000条不应该存在的指令,那么有人犯了一个很大的错误。纠正这个错误的方法是去掉那些本不该存在的2000条语句。解决方案是不改变语言的语义,这样
raise
语句就不会真正提出任何东西。这将使程序的长期维护变得更加困难。
 
procedure TestException(dwExceptionCode, dwExceptionFlags,
    nNumberOfArguments: DWORD; lpArguments: PDWORD); stdcall;
var
  Arg: array of DWORD absolute lpArguments;
begin
{$IFDEF DEBUG}
  if (nNumberOfArguments > 1) and Assigned(lpArguments) and
      (TObject(Arg[1]).ClassName = TMyErrorClass.ClassName) then begin
    ShowMessage('Test');
    TObject(Arg[1]).Free;
    Exit;
  end;
{$ENDIF}
  windows.RaiseException(dwExceptionCode, dwExceptionFlags,
                            nNumberOfArguments, lpArguments);

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  RaiseExceptionProc := @TestException;
  ..