9

假设我有以下例程:

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 例程中),如何避免它?

4

1 回答 1

12

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

版本 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异常处理程序链中向上传递。

旁白

你说:

我仍然觉得奇怪的是,在上面的构造中,finally 块在 except 块之后执行!

对于您问题中的代码(上述版本 1),情况并非如此。也许你还没有完全理解 finally 和 blocks 是如何运作的。

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

于 2015-03-04T21:54:38.470 回答