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

问题描述 投票:24回答:6

以下面的代码为示例:

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;

如果// do something节中发生错误,我假设创建的TSomeObject将不会被释放,而Screen.Cursor仍会像沙漏一样停留,因为在到达这些行之前代码已被破坏?

现在,除非我犯错,否则应该放置一个Exception语句来处理任何这样的错误发生,例如:

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

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

    Screen.Cursor:= crDefault;
  except on E: Exception do
  begin
    Obj.Free;
    Screen.Cursor:= crDefault;
    ShowMessage('There was an error: ' + E.Message);
  end;
end;

现在,除非我做的是真正愚蠢的事情,否则没有理由在Final块,之后块和Exception块中两次使用相同的代码。

[基本上,我有时会执行一些步骤,这些步骤可能与我发布的第一个示例相似,如果出现错误,则光标会像沙漏一样被卡住。添加Exception处理程序会有所帮助,但这似乎是一种肮脏的方式-它基本上忽略了Final块,更不用说从Final到Exception部分复制粘贴的丑陋代码了。

如果这似乎是直接的问题/答案,我仍在学习Delphi,因此深表歉意。

应该如何正确编写代码以处理语句并正确释放对象并捕获错误等?

delphi try-finally try-except
6个回答
33
投票

您只需要两个try/finally块:

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

遵循的准则是,您应使用finally而不是except来保护资源。如您所见,如果尝试使用except来执行此操作,那么您将不得不编写两次终结代码。

一旦输入try/finally块,无论finallytry之间发生什么,都保证finally部分中的代码可以运行。

因此,在上面的代码中,外部try/finally确保在遇到任何异常时都恢复Screen.Cursor。同样,内部try/finally可确保Obj在其生存期内出现任何异常的情况下被销毁。


如果要处理异常,则需要一个单独的try/except块。但是,在大多数情况下,您应该not尝试处理异常。只需让它传播到主应用程序异常处理程序,该处理程序将向用户显示一条消息。

如果您处理该异常以降低调用链,那么调用代码将不知道它调用的代码已失败。


17
投票

您的原始代码并没有您想像的那么糟糕(但是很糟糕):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;

Obj.Free 

将被执行,无论您何时// do something会发生什么。即使发生异常(在try之后),也会执行finally!这就是try..finally构造的重点!但是您也想还原光标。最好的方法是使用两个try..finally构造:

procedure TForm1.Button1Click(Sender: TObject); var Obj: TSomeObject; begin Screen.Cursor := crHourGlass; try Obj := TSomeObject.Create; try // do something finally Obj.Free; end; finally Screen.Cursor := crDefault; end; end;


15
投票
正如其他人所解释的,您需要使用try finally块来保护光标更改。为了避免编写这些代码,我使用如下代码:

2
投票
我会这样:

1
投票
我认为最“正确”的版本是这样:

1
投票
在服务/服务器中完成了大量需要处理异常且不会杀死应用程序的代码,我通常会选择类似的东西:
© www.soinside.com 2019 - 2024. All rights reserved.