Wrapping TStringList in a Record

delphi, records, tstringlist

Solution

It's possible. Create an interface that exposes the methods / objects you want:

type
  IStringList = interface
    procedure Add(const s: string); // etc.
    property StringList: TStringList read GetStringList; // etc.
  end;

Implement the interface, and have it wrap a real `TStringList`:

type
  TStringListImpl = class(TInterfacedObject, IStringList)
  private
    FStringList: TStringList; // create in constructor, destroy in destructor
    // implementation etc.
  end;

Then implement the record:

type
  TStringListRecord = record
  private
    FImpl: IStringList;
    function GetImpl: IStringList; // creates TStringListImpl if FImpl is nil
                                   // returns value of FImpl otherwise
  public
    procedure Add(const s: string); // forward to GetImpl.Add
    property StringList: TStringList read GetStringList; // forward to
                                                         // GetImpl.StringList
    // etc.
  end;

The fact that there's an interface inside the record means the compiler will handle reference counting automatically, calling _AddRef and _Release as copies get created and destroyed, so lifetime management is automatic. This works for objects that will never contain a reference to themselves (creating a cycle) - reference counting needs various tricks to get over cycles in the reference graph.

Problem

I tend to use Delphi's TStringList for text manipulation, so I write a lot of procedures/functions like: ``` var TempList: TStringList; begin TempList:= TStringList.Create; try // blah blah blah do stuff with TempList finally TempList.Free; end; end; ``` It would be nice to cut out the creation and freeing for such a common utility class. Since we now have records with methods, is it possible to wrap a Class like TStringList in a Record so I could just have: ``` var TempList: TRecordStringList; begin // blah blah blah do stuff with TempList end; ```

Original source