【问题标题】:FURTHER CLARIFICATION: How to correctly write Try..Finally..Except statements?进一步澄清:如何正确编写 Try..Finally..Except 语句?
【发布时间】:2013-12-06 11:50:46
【问题描述】:

回复:How to correctly write Try..Finally..Except statements?

我仍然对 OP 的原始问题感到困惑。具体来说,读取“Screen.Cursor:=crDefault”的过程的最后一行(try..finally..end 之外)。

我的理解是 try..except|finally..end 块中引发的任何异常在“try”的“end”之后执行代码。

procedure TForm1.Button1Click(Sender: TObject);
var
  Obj: TSomeObject;
begin
  Screen.Cursor := crHourGlass;

  Obj := TSomeObject.Create;
  try
    // do something
  finally
    Obj.Free;
  end;
  Screen.Cursor := crDefault;
end;

在上面的例子中,我看不出“Screen.Cursor:=crDefault”不会被执行的任何原因。如果我错了,请纠正我。

作为另一个示例,我编译了这段代码来帮助说明。运行代码时,将显示三 (3) 个 ShowMessage() 对话框。第一个“Exception Raised”,第二个“finally”,第三个“at end”。

procedure TForm1.Button1Click(Sender: TObject);
begin
   try
      try
         showMessage(format('%s', [12]));
      except
         showMessage('Exception raised');
      end;
   finally
      showMessage('finally');
   end;
   showMessage('at end');
end;

所以,我很困惑为什么他的“Screen.Cursor:=crDefault”没有以原始形式和代码运行。有人可以详细说明吗?

【问题讨论】:

    标签: delphi try-finally try-except


    【解决方案1】:

    您实际上并没有捕捉到异常。在这种情况下,一旦出现异常,“finally”代码块将执行,然后异常将展开堆栈。

    【讨论】:

    • 我不确定你的意思。异常被捕获并会说“引发异常”,然后会说“最后”,然后是“最后”。所有这 3 个 ShowMessage() 对话框都将显示尝试执行 format() 的结果,这将生成异常。简而言之,在这两个示例中都执行了过程中的最终操作。所以,我不明白为什么程序中的最后一行需要包含在 try..finally..end 中
    • 您在第二段代码中有“except”表达式,但在原始代码中没有。 “except”是捕获异常的东西,而不是“finally”
    【解决方案2】:

    您发布的代码似乎运行良好,因为您能够处理所有可能性。不过,请尝试对其进行一些更改,以便引发您的代码无法处理的异常:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      try
        try
          raise Exception.Create('42');
        except
          on E: EDivByZero do
            ShowMessage('DivByZero');
        end;
      finally
        ShowMessage('Finally');
      end;
      ShowMessage('Got here');
    end;
    

    运行此程序,您将看到Finally,然后是42 的异常,但没有Got here 消息。这是因为异常将你带出当前块,堆栈被展开,从 finally 的 end 到过程结束的代码永远不会执行。

    将最终的ShowMessage 调用从它所在的位置移动到finally 内部并再次运行。

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      try
        try
          raise Exception.Create('42');
        except
          on E: EDivByZero do
            ShowMessage('DivByZero');
        end;
      finally
        ShowMessage('Finally');
        ShowMessage('Got here');
      end;
      ShowMessage('Will never get here');
    end;
    

    您现在将在finally 块中看到对ShowMessage 的两个调用,一个接一个,但不是finally 块的end; 之后的一个。 finally 块内的代码保证会执行,而超出它的代码可能会也可能不会。

    为了更清楚,try..except 块的存在可以删除:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      try
        raise Exception.Create('42');
      finally
        ShowMessage('Finally');
        ShowMessage('Got here');
      end;
      ShowMessage('Will never get here');
    end;
    

    try..finally 块的全部目的是确保finally 部分内的代码将在过程结束之前执行。

    【讨论】:

    • 我想我对你的例子理解得更好。基本上,如果“except”有一个“on”子句,并且如果“on”子句没有处理异常,那就是坏事发生并且过程中的代码,在 try...end 之后没有执行.因此,任何时候使用 try..except..end AND 都会添加一个“on”子句来捕获特定异常;需要对这些代码块进行审核,以确保正确处理“except...on”捕获的任何异常NOT
    • @VinK:不完全是。如果根本没有except 子句,则可能会发生坏事并导致同样的问题。完全删除try..except..end,但保留raise 语句;您仍然会看到finally 结尾和过程结尾之间的代码不执行。 finally 块的全部目的是确保代码执行。它后面的代码可能无法运行
    • 知道了。感谢您澄清这种行为。
    • @Jerry:谢谢。我承认这是事后的想法。我在编辑期间从海报的12 更改了它。 :-) 不过,我希望这不是投票的真正原因。 :-(
    • 很好的答案,只是“讽刺”
    【解决方案3】:

    在 Delphi 中,finally 块并不能真正处理 try 块中发生的异常。它只保证finally 块中的代码将始终被执行,无论try 块中是否发生异常。如果那里确实发生了异常,则不会被捕获。而当一个异常没有被捕获时,你就知道它下面的代码发生了什么。

    要捕获可能发生的异常,请改用try...except... 块。您可以结合这两个构造来执行这两个操作:(1)保证执行某些代码,以及(2)捕获可能发生的异常。常见的用法是这样的:

    try
      try
        // do something that might cause an exception.
      finally
        // do something that must be executed WHATEVER happened.
      end;
    except
      // do something ONLY IF an exception has occured.
    end;
    

    因此,您应该更改代码并将Screen.Cursor := crDefault; 移动到finally 块内。此外,添加try...except... 块以包围try...finally... 块。像这样:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      Obj: TSomeObject;
    begin
      Screen.Cursor := crHourGlass;
      Obj := TSomeObject.Create;
      try
        try
          // do something.
        finally
          Obj.Free;
          Screen.Cursor := crDefault;
        end;
      except
        ShowMessage('An error has occured!');
      end;
    end;
    

    或者,如果您不确定代码 Obj := TSomeObject.Create; 是否足够安全,您应该添加第二个 try...finally... 块将其包围,如下所示:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      Obj: TSomeObject;
    begin
      Screen.Cursor := crHourGlass;
      try
        try
          Obj := TSomeObject.Create;
          try
            // do something.
          finally
            Obj.Free;
          end;
        finally
          Screen.Cursor := crDefault;
        end;
      except
        ShowMessage('An error has occured!');
      end;
    end;
    

    在那里,希望它有所帮助:)

    【讨论】:

      猜你喜欢
      • 2018-02-24
      • 1970-01-01
      • 2013-02-19
      • 1970-01-01
      • 2012-06-25
      • 1970-01-01
      • 1970-01-01
      • 2020-06-08
      相关资源
      最近更新 更多