进一步澄清:如何正确编写Try..Finally..Except语句?

时间:2013-11-21 19:55:43

标签: delphi try-finally try-except

RE:How to correctly write Try..Finally..Except statements?

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

我的理解是try1.except | finally..end块中引发的任何异常将的“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”没有被运行,原因是它的原始形式和代码。有人可以详细说明吗?

3 个答案:

答案 0 :(得分: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消息。这是因为异常将您从当前块中取出,堆栈被解除,并且从最终的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; 内,然后重新开始。

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块的整个目的是确保{{1}}部分内的代码在程序结束之前执行。

答案 1 :(得分:1)

你实际上没有捕获异常。在这种情况下,在异常时,将执行“finally”代码块,然后异常将展开堆栈。

答案 2 :(得分:1)

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

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