use*_*752 1 delphi exception-handling
假设我有三个(或更多)程序,其中一些程序互相调用,如下所示,其中任何一个程序都可能失败.
如果其中任何一个失败,我希望'main'程序立即记录失败并终止程序.
在Delphi中使用哪种正确的语法将异常"传回"到每个先前的过程调用?
如果有人可以帮助我获取主程序的Try/except块以确定哪个位失败,那就更好了!
三个程序和主程序的示例伪代码可能如下所示.
(我想我理解这个原理,与'raise'有关,但是想要一些实际语法和我应该使用的代码的帮助)
//////////////////////////////////////
Procedure DoProcA
begin
try
begin
{stuff}; //stuff that might fall
end;
except
on E : Exception do
begin
LogError ('error in A');
end //on E
end;//try
//////////////////////////////////////
Procedure DoProcB
begin
try
begin
Do ProcC; //another proc that might fail
{other stuff}
end;
except
on E : Exception do
begin
LogError ('error in B');
end //on E
end;//try
//////////////////////////////////////
Procedure DoProcC
begin
try
begin
{Do stuff} //even more stuf fthat might fail
end;
except
on E : Exception do
begin
LogError ('error in C');
end //on E
end;//try
//////////////////////////////////////
//Main programo
begin
try
DoProcA;
DoProcB;
{other stuff}
except
{here I want to be able to do something like
if failure of A, B or C then
begin
LogError ('Failure somewhere in A, B or C');
application.terminate;
end;}
end; //try
end.
Run Code Online (Sandbox Code Playgroud)
处理此问题的最佳方法是删除所有这些异常处理程序.使用像madExcept,EurekaLog,JCL Debug等库来记录任何异常,使其一直回到顶级异常处理程序.
试图为程序中的每个函数添加异常处理程序是站不住脚的.这根本不是如何使用异常的.作为一个广泛的规则,您应该将异常视为不应被捕获的事物.它们代表了异常行为,因此,通常情况下,它们被引发的函数不知道如何处理它们.
所以,停止尝试处理异常.作为指导原则,不要处理它们.如果他们一直到顶级异常处理程序,那么在那里处理它们.如果您使用上面提到的库之一,您将能够获得丰富的调试信息,以帮助您了解为什么首先引发异常.
让每个函数在记录后重新引发捕获的异常,例如:
Procedure DoProcA;
begin
try
{stuff}; //stuff that might fall
except
on E : Exception do
begin
LogError ('error in A');
raise; // <-- here
end;
end;
end;
Procedure DoProcB;
begin
try
DoProcC; //another proc that might fail
{other stuff}
except
on E : Exception do
begin
LogError ('error in B');
raise; // <-- here
end;
end;
end;
Procedure DoProcC;
begin
try
{Do stuff} //even more stuff that might fail
except
on E : Exception do
begin
LogError ('error in C');
raise; // <-- here
end;
end;
end;
begin
try
DoProcA;
DoProcB;
{other stuff}
except
on E: Exception do
begin
LogError ('Failure somewhere in A, B or C');
//Application.Terminate; // this is not useful unless Application.Run is called first
end;
end;
end.
Run Code Online (Sandbox Code Playgroud)
如果您希望主过程识别WHICH函数失败,则需要将该信息传递到异常链中,例如:
type
MyException = class(Exception)
public
WhichFunc: String;
constructor CreateWithFunc(const AWhichFunc, AMessage: String);
end;
constructor MyException.CreateWithFunc(const AWhichFunc, AMessage: String);
begin
inherited Create(AMessage);
WhichFunc := AWhichFunc;
end;
Procedure DoProcA;
begin
try
{stuff}; //stuff that might fall
except
on E : Exception do
begin
raise MyException.CreateWithFunc('DoProcA', E.Message); // <-- here
end;
end;
end;
Procedure DoProcB;
begin
try
DoProcC; //another proc that might fail
{other stuff}
except
on E : MyException do
begin
raise; // <-- here
end;
on E : Exception do
begin
raise MyException.CreateWithFunc('DoProcB', E.Message); // <-- here
end;
end;
end;
Procedure DoProcC;
begin
try
{Do stuff} //even more stuff that might fail
except
on E : Exception do
begin
raise MyException.CreateWithFunc('DoProcC', E.Message); // <-- here
end;
end;
end;
begin
try
DoProcA;
DoProcB;
{other stuff}
except
on E: MyException do
begin
LogError ('Failure in ' + E.WhichFunc + ': ' + E.Message);
end;
on E: Exception do
begin
LogError ('Failure somewhere else: ' + E.Message);
end;
end;
end.
Run Code Online (Sandbox Code Playgroud)
要么:
type
MyException = class(Exception)
public
WhichFunc: String;
constructor CreateWithFunc(const AWhichFunc, AMessage: String);
end;
constructor MyException.CreateWithFunc(const AWhichFunc, AMessage: String);
begin
inherited Create(AMessage);
WhichFunc := AWhichFunc;
end;
Procedure DoProcA;
begin
try
{stuff}; //stuff that might fall
except
on E : Exception do
begin
raise MyException.CreateWithFunc('DoProcA', E.Message); // <-- here
end;
end;
end;
Procedure DoProcB;
begin
try
DoProcC; //another proc that might fail
{other stuff}
except
on E : Exception do
begin
Exception.RaiseOuterException(MyException.CreateWithFunc('DoProcB', E.Message)); // <-- here
end;
end;
end;
Procedure DoProcC;
begin
try
{Do stuff} //even more stuff that might fail
except
on E : Exception do
begin
raise MyException.CreateWithFunc('DoProcC', E.Message); // <-- here
end;
end;
end;
var
Ex: Exception;
begin
try
DoProcA;
DoProcB;
{other stuff}
except
on E: Exception do
begin
Ex := E;
repeat
if Ex is MyException then
LogError ('Failure in ' + MyException(Ex).WhichFunc + ': ' + Ex.Message)
else
LogError ('Failure somewhere else: ' + Ex.Message);
Ex := Ex.InnerException;
until Ex = nil;
end;
end;
end.
Run Code Online (Sandbox Code Playgroud)