我今天早上有这个想法,避免嵌套的try finally如下
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;
通过利用接口的自动引用计数,我已经提出
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,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;
我的问题是:这是工作还是让我忽略了一些东西?
对我来说,这看起来很酷,并且通过减少嵌套数量,使代码更容易阅读。它也可以扩展为存储匿名方法的列表来运行,以执行诸如关闭文件,查询等的操作…
解决方法
是的,它有效。
也许唯一不同的是,原始代码的嵌套的try-finally块和使用引用计数对象来管理其他对象的生命周期的技术是如果有一个问题销毁任何对象会发生什么。如果任何对象被破坏时有异常,嵌套的try-finally块将确保任何剩余的对象仍然可以被释放。 TDoFinally中的TObjectList不这样做;如果列表中的任何项目不能被销毁,列表中的任何后续项目将被泄漏。
实际上,这不是一个真正的问题。没有析构函数应该抛出异常。如果是这样,没有任何方法可以从中恢复,所以没有任何事情会因为它而泄漏。您的程序应该暂时终止,因此整洁的清理程序并不重要。
顺便提一句,JCL已经提供了用于管理本地对象的生命周期的ISafeGuard和IMultiSafeGuard
接口。例如,您可以重写代码,如下所示:
uses JclSysUtils; procedure DoSomething; var T1,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;