2011-12-16 53 views
4

問題是:在引發異常後,我可以阻止它從它自己的構造函數傳播?考慮代碼波紋管:加薪被稱爲德爾福 - 異常處理它自己的構造函數後,它被提出

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. 

後,我怎樣才能終止異常,無添加的try /除外終於在那裏我養的例外呢?

LE:我有幾乎2000升這樣的一個應用程序......我試圖找出一個替代解決方案編寫錯誤處理它....

+1

如果你要在它被構建之前殺死它,爲什麼要在第一個地方舉起它?不要使用異常,只需顯示一個消息框。 – 2011-12-16 12:23:24

回答

3

的方式來停止異常傳播是用except來捕捉它。請注意,您不會在引發異常的位置寫入except,但是您希望它停止傳播的位置。

但是,您應該不會停止構造函數中引發的異常在該構造函數之外傳播。如果你這樣做,你的對象可能會被部分構建。

我相信,正如許多人所說的,當遇到錯誤並讓它們浮動到高級異常處理程序時,正確解決問題的方法正如許多其他人所說的。

0

使用Application.OnException在您的應用程序的頂層實現泛型異常處理行爲。例如:

Application.OnException := MainForm.DefaultExceptionHandler; 

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

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

繼續正常控制流程後,一個例外是一個壞主意恕我直言。

5

一旦你進入了一個raise說法,只有兩種方式,以避免與提高是例外經歷:

  • 擡起別的東西第一。從即將提出的異常的構造函數中,可以先創建並引發一個不同的異常。這將避免您的程序達到第一個raise聲明。

  • 終止線程沒有任何得到運行。您可以通過多種方式來完成此操作,其中包括ExitThread,HaltExitProcess,在這種情況下,這幾乎都是等價的。你的程序不會再運行了,但至少你已經阻止它提升這個異常!

無論是那些將解決你正在試圖解決這個問題,但他們做你的要求爲你的問題。底線是,無論您想要做什麼,在您啓動異常提升機制之後壓縮異常都是錯誤的方法。你不能打開鈴鐺,你不能提出異常。

1

當正在構造TMyErrorClass的實例時,它不知道它是否將爲raised。你要求打破語言異常處理的基本因果關係。我永遠不會把它放在生產代碼中,因爲它將是一個定時炸彈。享受(寫在Delphi 6):

type 
    TMyClass = class(TObject) 
    public 
    Name: string; 
    constructor Create; 
    end; 

type 
    REArguments = array[0..100] of DWORD; 
    PREArguments = ^REArguments; 

type 
    TRaiseExceptionProc = procedure (dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD; lpArguments: PREArguments); stdcall; 

var 
    RaiseExceptionProc_Old: TRaiseExceptionProc; 

procedure MyRaiseException(dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD; lpArguments: PREArguments); stdcall; 
var 
    raisedObject: TObject; 
begin 
    if @RaiseExceptionProc_Old <> nil then 
    begin 
    RaiseExceptionProc := @RaiseExceptionProc_Old; 
    RaiseExceptionProc_Old := nil; 

    raisedObject := Pointer(lpArguments^[1]); 
    if raisedObject is TMyClass then 
    begin 
     raisedObject.Free; 
    end 
    else 
    begin 
     TRaiseExceptionProc(RaiseExceptionProc)(dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments); 
    end; 
    end; 
end; 

constructor TMyClass.Create; 
begin 
    inherited; 
    Name := 'MyClass'; 
    RaiseExceptionProc_Old := RaiseExceptionProc; 
    RaiseExceptionProc := @MyRaiseException; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    raise TMyClass.Create; 
    ShowMessage('Continue without interruption.'); 
end; 
1

我知道這是醜陋的所有帳戶,但想分享。代碼並不修改的異常類,這就像一個全球性的異常處理程序,但它不會被提出,將繼續執行,就好像什麼也沒有發生:

  
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測試,我沒有否則它會起作用的想法。