假设我有三个(或更多)程序,其中一些程序互相调用,如下所示,其中任何一个程序都可能失败.
如果其中任何一个失败,我希望'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.
David Heffer.. 8
处理此问题的最佳方法是删除所有这些异常处理程序.使用像madExcept,EurekaLog,JCL Debug等库来记录任何异常,使其一直回到顶级异常处理程序.
试图为程序中的每个函数添加异常处理程序是站不住脚的.这根本不是如何使用异常的.作为一个广泛的规则,您应该将异常视为不应被捕获的事物.它们代表了异常行为,因此,通常情况下,它们被引发的函数不知道如何处理它们.
所以,停止尝试处理异常.作为指导原则,不要处理它们.如果他们一直到顶级异常处理程序,那么在那里处理它们.如果您使用上面提到的库之一,您将能够获得丰富的调试信息,以帮助您了解为什么首先引发异常.
处理此问题的最佳方法是删除所有这些异常处理程序.使用像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.
如果您希望主过程识别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.
要么:
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.