当前位置:  开发笔记 > 编程语言 > 正文

嵌套异常的正确方法是什么? - 使用Delphi

如何解决《嵌套异常的正确方法是什么?-使用Delphi》经验,为你挑选了2个好方法。

假设我有三个(或更多)程序,其中一些程序互相调用,如下所示,其中任何一个程序都可能失败.

如果其中任何一个失败,我希望'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等库来记录任何异常,使其一直回到顶级异常处理程序.

试图为程序中的每个函数添加异常处理程序是站不住脚的.这根本不是如何使用异常的.作为一个广泛的规则,您应该将异常视为不应被捕获的事物.它们代表了异常行为,因此,通常情况下,它们被引发的函数不知道如何处理它们.

所以,停止尝试处理异常.作为指导原则,不要处理它们.如果他们一直到顶级异常处理程序,那么在那里处理它们.如果您使用上面提到的库之一,您将能够获得丰富的调试信息,以帮助您了解为什么首先引发异常.



1> David Heffer..:

处理此问题的最佳方法是删除所有这些异常处理程序.使用像madExcept,EurekaLog,JCL Debug等库来记录任何异常,使其一直回到顶级异常处理程序.

试图为程序中的每个函数添加异常处理程序是站不住脚的.这根本不是如何使用异常的.作为一个广泛的规则,您应该将异常视为不应被捕获的事物.它们代表了异常行为,因此,通常情况下,它们被引发的函数不知道如何处理它们.

所以,停止尝试处理异常.作为指导原则,不要处理它们.如果他们一直到顶级异常处理程序,那么在那里处理它们.如果您使用上面提到的库之一,您将能够获得丰富的调试信息,以帮助您了解为什么首先引发异常.


如果你真的可以处理它,你应该只**处理**例外.不要实现盲目捕获所有异常.
惊人的downvote,我希望无效.
这种方法的另一个问题是,在引发RTL代码时,您将无法捕获它们。仅在您首先抓住它们的那一点上。但坦率地说,在每个函数中都放置一个异常处理程序简直就是疯狂。

2> Remy Lebeau..:

让每个函数在记录后重新引发捕获的异常,例如:

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.

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有