26 delphi try-finally try-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;
Run Code Online (Sandbox Code Playgroud)
如果在该// do something部分中发生错误,我创建的TSomeObject将不会被释放,并且Screen.Cursor仍然会被卡在一个小时玻璃中,因为代码在进入这些行之前已经被破坏了?
现在除非我误会,否则应该有一个异常声明来处理任何错误的发生,例如:
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;
Run Code Online (Sandbox Code Playgroud)
现在除非我做了一些非常愚蠢的事情,否则应该没有理由在Finally块和之后以及在Exception块中两次使用相同的代码.
基本上我有时会有一些程序可能类似于我发布的第一个样本,如果我收到错误,光标会被卡在小时玻璃上.添加Exception处理程序会有所帮助,但它似乎是一种肮脏的方式 - 它基本上忽略了Finally块,更不用说从Finally到Exception部分的复制粘贴的丑陋代码.
如果这似乎是一个直截了当的问题/答案,我仍然非常学习德尔福.
如何正确编写代码来处理语句并正确释放对象和捕获错误等?
Dav*_*nan 34
你只需要两个try/finally街区:
Screen.Cursor:= crHourGlass;
try
Obj:= TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
finally
Screen.Cursor:= crDefault;
end;
Run Code Online (Sandbox Code Playgroud)
遵循的准则是您应该使用finally而不是except保护资源.正如您所观察到的,如果您尝试使用它,except那么您将被迫编写两次最终化代码.
一旦你进入try/finally块,finally无论在try和之间发生什么,保证该部分中的代码都会运行finally.
因此,在上面的代码中,外部try/finally确保Screen.Cursor在面对任何异常时恢复.同样,内部try/finally确保Obj在其生命周期中出现任何异常时被销毁.
如果要处理异常,则需要一个不同的try/except块.然而,在大多数情况下,你应该不尝试处理异常.只是让它传播到主应用程序异常处理程序,它将向用户显示一条消息.
如果你处理异常以降低调用链,那么调用代码将不知道它调用的代码是否失败.
And*_*and 17
您的原始代码没有您想象的那么糟糕:
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;
Run Code Online (Sandbox Code Playgroud)
Obj.Free 无论你怎么样,都会被执行// do something.即使发生异常(之后try),也会执行该finally块!这是构造的全部意义!try..finally
但是你也想恢复光标.最迂腐的方式是使用两种try..finally结构:
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
Screen.Cursor := crHourGlass;
try
Obj := TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
finally
Screen.Cursor := crDefault;
end;
end;
Run Code Online (Sandbox Code Playgroud)
[但是,我也不介意
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;
Run Code Online (Sandbox Code Playgroud)
太多了.Obj.Free失败的风险非常低,但在这种情况下,对象不会被释放(// do something因为你不在里面而不会运行try),所以双重finally更安全.
ain*_*ain 15
正如其他人所解释的那样,您需要使用try finally块保护光标更改.为了避免写这些,我使用这样的代码:
unit autoCursor;
interface
uses Controls;
type
ICursor = interface(IInterface)
['{F5B4EB9C-6B74-42A3-B3DC-5068CCCBDA7A}']
end;
function __SetCursor(const aCursor: TCursor): ICursor;
implementation
uses Forms;
type
TAutoCursor = class(TInterfacedObject, ICursor)
private
FCursor: TCursor;
public
constructor Create(const aCursor: TCursor);
destructor Destroy; override;
end;
{ TAutoCursor }
constructor TAutoCursor.Create(const aCursor: TCursor);
begin
inherited Create;
FCursor := Screen.Cursor;
Screen.Cursor := aCursor;
end;
destructor TAutoCursor.Destroy;
begin
Screen.Cursor := FCursor;
inherited;
end;
function __SetCursor(const aCursor: TCursor): ICursor;
begin
Result := TAutoCursor.Create(aCursor);
end;
end.
Run Code Online (Sandbox Code Playgroud)
现在你就像使用它一样
uses
autoCursor;
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
__SetCursor(crHourGlass);
Obj:= TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
end;
Run Code Online (Sandbox Code Playgroud)
和Delphi的引用计数接口机制负责恢复游标.
我认为最“正确”的版本是这样的:
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
Obj := NIL;
Screen.Cursor := crHourGlass;
try
Obj := TSomeObject.Create;
// do something
finally
Screen.Cursor := crDefault;
Obj.Free;
end;
end;
Run Code Online (Sandbox Code Playgroud)