1

RE:如何正确编写 Try..Finally..Except 语句?

我仍然对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() 对话框。第一个“异常引发”,第二个“最终”和第三个“结束”。

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”没有以原始形式和代码运行。有人可以详细说明吗?

4

3 回答 3

11

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

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消息。这是因为异常将你带出当前块,堆栈被展开,从endfinally 到过程结束的代码永远不会执行。

将最终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;

您现在将看到块ShowMessage中的两个调用finally,一个接一个,但不是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部分内的代码将在过程结束之前执行。

于 2013-11-21T20:08:30.453 回答
2

在 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;

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

于 2013-11-22T03:05:50.410 回答
1

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

于 2013-11-21T20:02:59.387 回答