如何正确编写Try..Finally..Except语句?
以下面的代码为例:
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 some
部分发生错误,我认为创建的 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 块中。
基本上,我有时会执行一些可能与我发布的第一个示例类似的过程,如果出现错误,光标会像沙漏一样卡住。添加异常处理程序有帮助,但这似乎是一种肮脏的方法 - 它基本上忽略了Finally块,更不用说从Finally复制粘贴到Exception部分的丑陋代码了。
我仍然在学习 Delphi,所以如果这看起来是一个简单的问题/答案,我深表歉意。
应该如何正确编写代码来处理语句并正确释放对象和捕获错误等?
Take the following code as a sample:
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;
if there was an error happening in the // do something
section, the TSomeObject that was created I assume will not be freed and the Screen.Cursor will still be stuck as an Hour Glass, because the code was broke before getting to those lines?
Now unless I am mistaking, an Exception statement should be in place to deal with any such occurence of an error, something like:
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;
Now unless I am doing something really stupid, there should be no reason to have the same code twice in the Finally block and after, and in the Exception block.
Basically I sometimes have some procedures that may be similar to the first sample I posted, and if I get an error the cursor is stuck as an Hour Glass. Adding the Exception handlers help, but it seems a dirty way of doing it - its basically ignoring the Finally block, not to mention ugly code with copy-paste from the Finally to Exception parts.
I am still very much learning Delphi so apologies if this appears to be a straight forward question/answer.
How should the code be correctly written to deal with the Statements and correctly freeing objects and capturing errors etc?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您只需要两个
try/finally
块:要遵循的准则是您应该使用
finally
而不是except
来保护资源。正如您所观察到的,如果您尝试使用except
来执行此操作,那么您将被迫编写两次最终代码。一旦进入
try/finally
块,无论try
和之间发生什么,
。finally
部分中的代码都保证运行>最后因此,在上面的代码中,外部
try/finally
确保在遇到任何异常时恢复Screen.Cursor
。同样,内部的try/finally
确保Obj
在其生命周期内发生任何异常时被销毁。如果您想处理异常,那么您需要一个不同的
try/ except
块。但是,在大多数情况下,您不应该尝试处理异常。只需让它传播到主应用程序异常处理程序,该处理程序将向用户显示一条消息。如果您处理异常以降低调用链,那么调用代码将不知道它调用的代码已失败。
You just need two
try/finally
blocks:The guideline to follow is that you should use
finally
rather thanexcept
for protecting resources. As you have observed, if you attempt to do it withexcept
then you are forced to write the finalising code twice.Once you enter the
try/finally
block, the code in thefinally
section is guaranteed to run, no matter what happens betweentry
andfinally
.So, in the code above, the outer
try/finally
ensures thatScreen.Cursor
is restored in the face of any exceptions. Likewise the innertry/finally
ensures thatObj
is destroyed in case of any exceptions being raised during its lifetime.If you want to handle an exception then you need a distinct
try/except
block. However, in most cases you should not attempt to handle exceptions. Just let it propagate up to the main application exception handler which will show a message to the user.If you handle the exception to low down the call chain then the calling code will not know that the code it called has failed.
正如其他人所解释的,您需要使用
try finally
块来保护光标更改。为了避免编写这些代码,我使用如下代码:现在您只需像使用它一样
,Delphi 的引用计数接口机制就会负责恢复光标。
As others have explained, you need to protect the cursor change with
try finally
block. To avoid writing those I use code like this:Now you just use it like
and Delphi's reference counted interface mechanism takes care of restoring the cursor.
您的原始代码并不像您想象的那么糟糕(尽管很糟糕):
无论发生什么,
Obj.Free
都会被执行当你//做某事
时。即使发生异常(在try
之后),finally
块也会被执行!这就是try..finally
构造的全部要点!但您还想恢复光标。最好的方法是使用两个
try..finally
结构:Your original code isn't quite as bad as you think (it's bad, though):
Obj.Free
will be executed no matter what happens when you// do something
. Even if an exception occurrs (aftertry
), thefinally
block will be executed! That is the whole point of thetry..finally
construct!But you also want to restore the cursor. The best way is to use two
try..finally
constructs:我认为最“正确”的版本是这样的:
I think the most "correct" version would be this:
如果您在这里找到了方法,并且正在寻找如何在 Delphi 中从 C# 构建
try- except-finally
构造:答案是您不能直接执行此操作。相反,正如 @sacconago 所暗示的,按如下方式嵌套
try
块:Delphi 的一个很好的功能是您可以将块嵌套为
try... except...finally
或try...finally... except
,尽管前者更常见。If you found your way here and were looking for how you make a
try-except-finally
construct from C# in Delphi:The answer is that you cannot do this directly. Instead, as @sacconago hints at, nest the
try
blocks as follows:One nice feature of Delphi is that you can nest the blocks as
try...except...finally
ortry...finally...except
, though the former would be more common.在服务/服务器中完成了大量需要处理异常而不是终止应用程序的代码后,我通常会这样做:
注意最后的尝试;在 try except 内;以及 Obj 创建的位置。
如果 Obj 在其构造函数内创建其他内容,则它可能会中途工作并失败,并在 .create() 内出现异常;但仍然是一个创建的 Obj。所以我确保如果 Obj 被分配,它总是被销毁......
Having done a lot of code in services/servers that needs to handle exceptions and not kill the app I usually go for something like this:
Note the try finally; inside the try except; and the placement of Obj creation.
if the Obj creates other things inside it's constructor, it may work half-way and fail with an exception inside the .create(); but still be a created Obj. So I make sure that the Obj is always destroyed if it's been assigned...
我会这样做:
I would do it like this: