How to serialize Delphi object

It has been a very lean and easy option of .Net to able serialize/deserialize any serializable object instance.

Only closest option in Delphi is to stream the component using WriteComponent/WriteComponentRes of TStream/TWriter (used for Form storage as DFM, for example). It can be then read back using appropriate counterpart ReadComponent/ReadComponentRes.

Depend on your situation, simply calling .Assign method would work if you are coping data from one instance to another. But it only works between inherited classed which know about each other.

Can we find there something which will allow to pass objects states in more readable format?

There is a very powerful infrastructure available to do full serialization without knowing underlying class structure – RTTI (Run-time Type Information).

All functions we would be looking at are defined in TypInfo.pas unit.

First thing first. To be able to work within RTTI, you need to operate on the object which has published and public properties.

function GetPropList(TypeInfo: PTypeInfo;  out APropList: PPropList): integer;

A function will return number and reference to the list (array) of properties published (public and published) by the class (VMT information). List will also include published methods. Simply walking through it will give you an access to property/method information.

In our example we are not interested in the published methods, so lets filter it out:

var
  i: integer;
  lPropInfo: PPropInfo;
  lPropCount: integer;
  lPropList: PPropList;
  lPropType: PPTypeInfo;
begin
  lPropCount := GetPropList(PTypeInfo(AObject.ClassInfo), lPropList);
  for i := 0 to lPropCount - 1 do
  begin
   lPropInfo := lPropList^[i];
    lPropType := lPropInfo^.PropType;
    if lPropType^.Kind = tkMethod then
    Continue;
  // ... processing of the properties ...
  end;
end;

What other Kind of information is present in the list? Bellow is full definition of the type

type
  TTypeKind = (tkUnknown, tkInteger, tkChar, tkEnumeration,
tkFloat, tkString, tkSet, tkClass, tkMethod, tkWChar,
tkLString, tkWString, tkVariant, tkArray, tkRecord,
tkInterface, tkInt64, tkDynArray);

Now you are ready to get or set the value of the property:

function GetPropValue(Instance: TObject; const PropName: string;
  PreferStrings: Boolean = True): Variant;
procedure SetPropValue(Instance: TObject; const PropName: string;
  const Value: Variant);

And now you are ready to serialize your object, store it, load definition and deserialize an object back. And it could be not necessarily the same object.
You would have to loop through the properties, read the values, and store it as an XML for later use.

I am not going to go through all specific details in this post, instead, you can find a full code for XML Class serializer here.

This entry was posted in Delphi and tagged , , , , , , , , , . Bookmark the permalink.

20 thoughts on “How to serialize Delphi object”

  1. A new version has been uploaded to the website
    Only unprocessed properties are set when deserializing an object, preventing double processing mentioned by stoxx.

  2. Dorin says:

    Hm… just a short review of source, it seems, doesn’t work with references, am I right?

  3. What do you mean? References to external object instances?
    Under StorageOptions, enable soIncludeObjectLinks.

  4. Stefan says:

    Hi,
    i try to read a serialized TCollection descendant, but i dont dont work for me.
    The code stops in the following line:
    if IsPublishedProp(aPropertyInstance, lPropName) and Assigned(lPropInfo^.SetProc) then
    lPropInfo.SetProc is nil for the Count-Property (because its a read-only property!).
     
    Any suggestions?
    Stefan

  5. Stefan,
    You cannot deserialize read-only properties
    Do you have a sample which would demonstrate the problem?

  6. Stefan says:

    hi

    i got the following classes:

    type TStorageItem = class(TCollectionItem)
     private
     M_sText: String;
     published
     property Text: String read M_sText write M_sText;
    end;
    type TStorage = class(TCollection)
     private
     function GetItem(Index: Integer): TStorageItem;
     procedure SetItem(Index: Integer; const Value: TStorageItem);
     public
     function Add: TStorageItem;
     function FindItemID(ID: Integer): TStorageItem;
     function Insert(Index: Integer): TStorageItem;
     property Items[Index: Integer]: TStorageItem read GetItem write SetItem;
    end;
    

    which i serialize with the following code:

    with TXMLSerializer.Create(self) do
     begin
     XMLSettings.WellFormated := true;
     StorageOptions := [soIncludeObjectLinks, soSortProperties];
     SpecialClasses := [scTCollection];
     SaveObject(coTest, 'Test');
     SaveToFile('C:\test.xml');
     end;

    This works fine! I get a xml-file in a format which i excpect.

    If i try to read this object back from the xml-file it just dont work:

    var
     coTest: TStorage;
     coStore: TStorageItem;
     i: Integer;
    begin
     coTest := TStorage.Create(TStorageItem);
     with TXMLSerializer.Create(self) do
     begin
     XMLSettings.WellFormated := true;
     SpecialClasses := [scTCollection];
     LoadFromFile('C:\test.xml');
     LoadObject(coTest, 'Test');
     end;
     ListBox1.Clear;
     for i := 0 to coTest.Count - 1 do
     begin
     ListBox1.AddItem(coTest.Items[i].Text, nil);
     end;

    Greets,
    Stefan

  7. this kind of class property definition is not supported
    You need to modify it as following

    type
      TStorageItem = class(TCollectionItem)
      private
        FText: String;
        function GetM_sText: string;
        procedure SetM_sText(Value: string);
      published
      property Text: String read GetM_sText write SetM_sText;
      end;
  8. Luca says:

    Hello,

    Very nice component, congratulations.

    It seems to work only with published (not public) properties, so arrays are not supported, am I right?

    You need some fixes to work with Delphi 2009, e.g. in functions SaveToFile and LoadFromFile you have to switch to AnsiString.

    Regards,
    Luca

Leave a Reply

  • About

    From being a junior developer all the way to Development Manager position, I was always interested in new technologies. Passionate speaker, IT junky, developer, architect, team lead, and development manager - many hats, one goal - making software better and closer to people’s needs. For the most part I am using my blog as a scratch pad, writing small articles on things which I came across, was asked about more then once, and which would otherwise require additional research again and again.

    View Serguei Dosyukov's profile on LinkedIn
  • Testimonials

    I’m a huge fan of this theme. I’ve got more than 90,000 pictures in my gallery3 running on a Ubuntu...

    Jklobo

    I've been using this [theme] since the start. It is by far the most attractive, feature packed and stable of...

    Rhyull

    The greydragon theme is fantastic. It’s clean, stable and feature rich. It took me a while to decide to move...

    Ed

    more...

  • Categories