Icon View Thread

The following is the text of the current message along with any replies.
Messages 1 to 3 of 3 total
Thread Recursive components
Wed, Jun 15 2016 8:02 AMPermanent Link

Matthew Jones

How can I serialise a recursive component?

I have a tree of TTreeItems. The root can have zero or more child
TTreeItems, stored in a list. In my first implementation, I used a
TObjectList, but then I went to serialise to/from JSON and used a
separate class which represents the list, and can serialise it, thus
creating TTreeItemList. However, it needs to know about TTreeItem's,
and since the TTreeItem contains the TTreeItemList, I get stuck in an
uncompilable loop.

Okay, so Delphi fixes this with a forward reference in a unit, so you
can do something like:

TTreeItemList = class; // forward reference

TTreeItem = class (TPersistent)
// ... real implementation

TTreeItemList = class (TPersistent)
// ... real implementation

Is there a way to do this? This is mentioned in the help, but no
solution offered. I wonder if there is a way to make the published
property different somehow? It is

property ChildList : TTreeItemList read m_xChildList write m_xChildList;

If that was a TObject, the normal way to handle this, can I intercept
the serialisation and do the proper conversion?

--

Matthew Jones
Wed, Jun 15 2016 8:13 AMPermanent Link

Matthew Jones

Matthew Jones wrote:

> If that was a TObject, the normal way to handle this, can I intercept
> the serialisation and do the proper conversion?

Of course you can!

procedure TTreeItem.SaveProperties(AWriter: TWriter);
begin
   inherited SaveProperties(AWriter);
   TTreeItemList(m_xChildItemList).SaveProperties(AWriter);
end;

And for completeness, the list's version:

procedure TJSONList.SaveProperties(AWriter: TWriter);
var
   nWriteLoop : Integer;
   xItem : TPersistent;
begin
   inherited SaveProperties(AWriter);

   AWriter.PropertyName(JSONArrayName);
   AWriter.BeginArray(m_xList.Count > 0); // hasElements param
controls the output of spaces

   for nWriteLoop := 0 to m_xList.Count - 1 do
   begin
       if not m_xList.Objects[nWriteLoop] is TPersistent then
           raise Exception.Create('Object in list is not persistent');
       xItem := TPersistent(m_xList.Objects[nWriteLoop]);
       xItem.Save(AWriter);
       if nWriteLoop < m_xList.Count - 1 then
           AWriter.Separator;
   end;
   AWriter.EndArray(m_xList.Count > 0); // hasElements param controls
the output of spaces
end;

--

Matthew Jones
Wed, Jun 15 2016 8:27 AMPermanent Link

Matthew Jones

Matthew Jones wrote:

> And for completeness, the list's version:

And for complete completeness, you will find that the TObject is
serialised too (of course). So either stop it being a published
property, or add:

procedure TTreeItem.SaveProperty(AWriter: TWriter; const AName: String);
begin
   if AName <> 'childitemlist' then
       inherited SaveProperty(AWriter, AName);
end;

The former is easiest of course.

--

Matthew Jones
Image