Delphi - except 和 finally 块的 "correct" 顺序是什么?

Delphi - What is the "correct" order for except and finally blocks?

假设我有以下例程:

function ReadFile(f : TFilename) : Boolean;
var
  fs : TFileStream;
begin
  Result := False;
  try
    fs := TFileStream.Create(f, ...);
    try
      // read file ...
      Result := True;
    finally
      FreeAndNil(fs);
    end;
  except
    // handle exceptions ...
  end;
end;

exceptfinally 转置有什么含义?我已经看到很多关于它们的帖子,但是我还没有看到关于在什么情况下哪个合适的明确解释(我仍然认为在上面的构造中, finally 块执行 except 块之后!)。

我也看到一些帖子暗示混合 try..excepttry..finally 块不是一个好主意。在例程抛出异常作为正常操作的一部分的情况下如何避免它 - 例如在某些 Indy 例程中?

没有唯一正确的写法。这两个变体做不同的事情。您可能在一种情况下更喜欢一个版本,在不同的情况下更喜欢另一个。

版本 1,终于在最里面了

function ReadFile(f : TFilename) : Boolean;
var
  fs : TFileStream;
begin
  Result := False;
  try
    fs := TFileStream.Create(f, ...);
    try
      // read file ...
      Result := True;
    finally
      FreeAndNil(fs);
    end;
  except
    // handle exceptions ...
  end;
end;

版本 2,最后是最外层

function ReadFile(f : TFilename) : Boolean;
var
  fs : TFileStream;
begin
  Result := False;
  fs := TFileStream.Create(f, ...);
  try
    try
      // read file ...
      Result := True;
    except
      // handle exceptions ...
    end;
  finally
    FreeAndNil(fs);
  end;
end;

最大的区别在于如果 TFileStream.Create 引发异常,代码的行为方式远非难以置信。在版本 1 中,异常将在 ReadFile 中被捕获和处理。在版本 2 中,异常将从 ReadFile 传递到异常处理程序链上。

旁白

您说:

I still think it is curious that in the above construct, the finally block executes after the except block!

上面第 1 版问题​​中的代码并非如此。也许你还没有完全理解 finally 和 blocks 是如何运行的。

经常观察到的一个常见错误是希望尽快捕获和处理异常。那是错误的策略。关于异常的全部要点是它不是注定要发生的,而且当它确实发生时您通常不知道该怎么做。您的目标是尽可能晚地处理异常。对于绝大多数代码,您根本不应该处理异常。让它们向上浮动到代码中能够处理错误的点。