在Delphi中避免嵌套try ... finally块 [英] Avoiding nested try...finally blocks in Delphi

查看:270
本文介绍了在Delphi中避免嵌套try ... finally块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天早上我有这个想法,避免嵌套尝试最后的块,如下所示

I had this idea this morning on avoiding nested try finally blocks like the following

procedure DoSomething;
var
  T1, T2, T3 : TTestObject;
begin
  T1 := TTestObject.Create('One');
  try
    T2 := TTestObject.Create('Two');
    try
      T3 := TTestObject.Create('Three');
      try
        //A bunch of code;
      finally
        T3.Free;
      end;
    finally
      T2.Free;
    end;
  finally
    T1.Free;
  end;
end;

通过利用接口的自动引用计数,我想出了

By taking advantage of the automated reference counting of interfaces, I have come up with

Type  
  IDoFinally = interface
    procedure DoFree(O : TObject);
  end;

  TDoFinally = class(TInterfacedObject, IDoFinally)
  private
    FreeObjectList : TObjectList;
  public
    procedure DoFree(O : TObject);
    constructor Create;
    destructor Destroy; override;
  end;

//...

procedure TDoFinally.DoFree(O : TObject);
begin
  FreeObjectList.Add(O);
end;

constructor TDoFinally.Create;
begin
  FreeObjectList := TObjectList.Create(True);
end;

destructor TDoFinally.Destroy;
begin
  FreeObjectList.Free;
  inherited;
end;

以前的代码块变为

procedure DoSomething;
var
  T1, T2, T3 : TTestObject;
  DoFinally : IDoFinally;
begin
  DoFinally := TDoFinally.Create;
  T1 := TTestObject.Create('One');
  DoFinally.DoFree(T1);
  T2 := TTestObject.Create('Two');
  DoFinally.DoFree(T2);
  T3 := TTestObject.Create('Three');
  DoFinally.DoFree(T3);
  // A Bunch of code;
end;

我的问题是:这有用还是我忽略了什么?

My question is: does this work or have I overlooked something?

对我而言,这看起来非常酷,并且通过减少嵌套量使代码更容易阅读。它还可以扩展为存储一系列匿名方法来运行以执行诸如关闭文件,查询等操作...

To me this looks pretty cool, and makes the code a bit easier to read with the reduced amount of nesting. It could also be extended to store a list of anonymous methods to run to do things such as close files, queries, etc...

推荐答案

是的,它有效。

也许唯一不同的是原始代码的嵌套try-finally块和技术之间的区别如果存在破坏任何对象的问题,则使用引用计数对象来管理其他对象的生命周期。如果在销毁任何对象时出现异常,嵌套的try-finally块将确保仍然可以释放任何剩余的对象。 TDoFinally 中的 TObjectList 不会这样做;如果列表中的任何项目都无法销毁,列表中的任何后续项目都将被泄露。

Perhaps the only thing different between the nested try-finally blocks of the original code and the technique of using a reference-counted object to manage the lifetimes of other objects is what happens if there's a problem destroying any of the objects. If there's an exception while any object is being destroyed, the nested try-finally blocks will ensure that any remaining objects will still get freed. The TObjectList in your TDoFinally doesn't do that; if any item in the list can't be destroyed, any subsequent items in the list will be leaked.

实际上,这不是一个真正的问题。没有析构函数应该抛出异常。如果确实如此,那么无论如何都没有任何方法可以从中恢复,因此如果有任何泄漏则无关紧要。你的程序应该暂时终止,所以整理清理程序并不重要。

In practice, that's not really a problem, though. No destructor should ever throw an exception. If it does, there's not really any way to recover from it anyway, so it doesn't matter if anything leaks because of it. Your program should terminate momentarily anyway, so having a tidy cleanup routine is of little importance.

顺便提一下,JCL已经提供 ISafeGuard IMultiSafeGuard 用于管理的界面本地物体的生命周期。例如,您可以像这样重写代码:

Incidentally, the JCL already offers the ISafeGuard and IMultiSafeGuard interfaces for managing local objects' lifetimes. For example, you could rewrite your code like this:

uses JclSysUtils;

procedure DoSomething;
var
  T1, T2, T3: TTestObject;
  G: IMultiSafeGuard;
begin
  T1 := TTestObject(Guard(TTestObject.Create('One'), G));
  T2 := TTestObject(Guard(TTestObject.Create('Two'), G));
  T3 := TTestObject(Guard(TTestObject.Create('Three'), G));
  // A Bunch of code;
end;

该库也不解决析构函数中的异常。

That library doesn't address exceptions in destructors, either.

这篇关于在Delphi中避免嵌套try ... finally块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆