假设我有以下例程:
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;
让except
和finally
换位有什么含义?我已经看过很多关于它们的帖子,但是我还没有看到一个明确的解释,哪些情况适合哪些情况(我仍然认为在上面的构造中,finally
块很奇怪在 except
块后执行!)。
我还看过一些帖子,表明混合try..except
和try..finally
块并不是一个好主意。如果例程在正常操作中抛出异常(例如在某些Indy例程中),如何避免它?
答案 0 :(得分: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不是这样。也许你还没有完全理解最终和块如何运作。
经常观察到的一个常见错误是希望尽快捕获和处理异常。这是错误的策略。关于异常的全部意义在于它并不意味着发生,并且当它确实发生时你通常不知道该怎么做。您的目标是尽可能晚地处理异常。对于绝大多数代码,您应该根本不处理异常。让它们向上浮动到代码中能够处理错误的点。