您是否知道在Delphi代码中捕获,记录和重新引发异常的方法? 一个简单的例子:
procedure TForm3.Button1Click(Sender: TObject);
begin
try
raise Exception.Create('Bum');
except
on E: Exception do
begin
MyHandleException(E);
end;
end;
end;
procedure TForm3.MyHandleException(AException: Exception);
begin
ShowMessage(AException.Message);
LogThis(AException.Message);
// raise AException; - this will access violate
end;
所以我需要在except块中重新提升它,但我想知道是否有更好的方法来编写我自己的方法来处理和(在特定条件下)重新引发异常。
答案 0 :(得分:31)
如果您只想在特定条件下重新引发异常,请写
procedure TForm3.Button1Click(Sender: TObject);
begin
try
raise Exception.Create('Bum');
except
on E: Exception do
begin
if MyHandleException(E) then
raise;
end;
end;
end;
function TForm3.MyHandleException(AException: Exception): boolean;
begin
ShowMessage(AException.Message);
result := true/false;
end;
答案 1 :(得分:9)
继Craig Young的帖子之后,我已经成功地使用了以下代码中的内容。您可以使用" at"保留原始例外位置。带有ExceptAddr函数的标识符。原始异常类类型和信息也会保留。
procedure MyHandleException(AMethod: string);
var
e: Exception;
begin
e := Exception(AcquireExceptionObject);
e.Message := e.Message + ' raised in ' + AMethod;
raise e at ExceptAddr;
end;
try
...
except
MyHandleException('MyMethod');
end;
答案 2 :(得分:6)
以下方法可行,但由于以下两个原因当然不理想:
procedure TForm3.MyHandleException(AException: Exception);
begin
ShowMessage(AException.Message);
LogThis(AException.Message);
raise ExceptClass(AException.ClassType).Create(AException.Message);
end;
好处是您可以保留原始异常类和消息(以及您希望复制的任何其他属性)。
理想情况下,您需要调用System._RaiseAgain
,但唉,这是一个'编译器 - 魔术'例程,只能由raise;
调用。
答案 3 :(得分:4)
您可以尝试使用(system.pas):
function AcquireExceptionObject: Pointer;
AcquireExceptionObject返回指向当前异常对象的指针,并防止在当前异常处理程序退出时释放异常对象。
注意:AcquireExceptionObject会增加异常对象的引用计数。确保在不再需要异常对象时递减引用计数。如果您使用异常对象重新引发异常,则会自动发生这种情况。在所有其他情况下,每次调用AcquireExceptionObject都必须匹配对ReleaseExceptionObject的调用。可以嵌套AcquireExceptionObject / ReleaseExceptionObject序列。
答案 4 :(得分:2)
您应该能够仅使用Raise
命令重新引发异常:
begin
MyHandleException(E);
Raise;
end;
答案 5 :(得分:1)
旧主题但是,这个解决方案呢?
procedure MyHandleException(AException: Exception);
begin
ShowMessage(AException.Message);
AcquireExceptionObject;
raise AException;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
try
raise Exception.Create('Bum');
except
on E: Exception do
MyHandleException(E);
end;
end;
它基于Eduardo发布的第一个代码。
答案 6 :(得分:1)
这种方式对我有用!
procedure RaiseExceptionFmt(const AFormat: string;
const AArgs: array of const);
begin
raise Exception.CreateFmt(AFormat, AArgs) at ExceptAddr;
end;
我改写了我的方法,现在加薪以前是一样的。
procedure RaiseInternalExceptionFmt(const AFormat: string;
const AArgs: array of const);
var
LExceptionPtr: Pointer;
begin
LExceptionPtr := AcquireExceptionObject();
try
Exception(LExceptionPtr).Message := Format(AFormat, AArgs);
raise Exception(LExceptionPtr) at ExceptAddr;
finally
ReleaseExceptionObject();
end;
end;
答案 7 :(得分:0)
您可以在调用处理程序之前获取异常对象,并将处理程序本身保持为一个衬里。但是,你仍然有很多“尝试/接受/做/结束”的负担。
Procedure MyExceptionHandler(AException: Exception);
Begin
Log(AException); // assuming it accepts an exception
ShowMessage(AException.Message);
raise AException; // the ref count will be leveled if you always raise it
End;
Procedure TForm3.Button1Click(Sender: TObject);
Begin
Try
Foo;
Except On E:Exception Do
MyExceptionHandler(Exception(AcquireExceptionObject));
End;
End;
但是,如果您只想在事件处理程序中删除重复的错误处理代码,那么您可以尝试这样做:
Procedure TForm3.ShowException(AProc : TProc);
Begin
Try
AProc;
Except On E:Exception Do Begin
Log(E);
ShowMessage(E.Message);
End; End;
End;
将事件处理程序代码减少到:
Procedure TForm3.Button1Click(Sender: TObject);
Begin
ShowException(Procedure Begin // anon method
Foo; // if this call raises an exception, it will be handled by ShowException's handler
End);
End;
您还可以使用参数化函数使其适用于函数:
Function TForm3.ShowException<T>(AFunc : TFunc<T>) : T;
Begin
Try
Result := AFunc;
Except On E:Exception Do Begin
Log(E);
ShowMessage(E.Message);
End; End;
End;
使ShowException返回一个值(充当passthru):
Procedure TForm3.Button1Click(Sender: TObject);
Var
V : Integer;
Begin
V := ShowException<Integer>(Function : Integer Begin // anon method
Result := Foo; // if this call raises an exception, it will be handled by ShowException's handler
End);
End;
甚至使anon程序直接触摸外部范围变量:
Procedure TForm3.Button1Click(Sender: TObject);
Var
V : Integer;
Begin
ShowException(Procedure Begin // anon method
V := Foo; // if this call raises an exception, it will be handled by ShowException's handler
End);
End;
匿名函数体内的变量与外部范围中定义的变量之间存在一些限制,但对于像这样的简单情况,你会更好。