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; So that the previous block of code becomes
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...
Add()will raise an exception if there is a problem with memory, so you would have to use atry/exceptblock to ensure untracked objects still get freed.