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;
将 except
和 finally
转置有什么含义?我已经看到很多关于它们的帖子,但是我还没有看到关于在什么情况下哪个合适的明确解释(我仍然认为在上面的构造中, finally
块执行 在 except
块之后!)。
我也看到一些帖子暗示混合 try..except
和 try..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 是如何运行的。
经常观察到的一个常见错误是希望尽快捕获和处理异常。那是错误的策略。关于异常的全部要点是它不是注定要发生的,而且当它确实发生时您通常不知道该怎么做。您的目标是尽可能晚地处理异常。对于绝大多数代码,您根本不应该处理异常。让它们向上浮动到代码中能够处理错误的点。
假设我有以下例程:
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 例程中?
没有唯一正确的写法。这两个变体做不同的事情。您可能在一种情况下更喜欢一个版本,在不同的情况下更喜欢另一个。
版本 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 是如何运行的。
经常观察到的一个常见错误是希望尽快捕获和处理异常。那是错误的策略。关于异常的全部要点是它不是注定要发生的,而且当它确实发生时您通常不知道该怎么做。您的目标是尽可能晚地处理异常。对于绝大多数代码,您根本不应该处理异常。让它们向上浮动到代码中能够处理错误的点。