Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion

Ng serialization : Serializing an objects list

I've made so test trying to serialize objects list. Here are a few remarks that I hope will help other users :

Serializing objects list :

- Ngs (NgSerializor) needs to use converters

- for each object list class we need to have an attribut indicating the converter to use

- Different object list class can use the same converter if they deal with objects descendants of the base list using the convertor

- object list cannot be deserialize directly, they must be owned by an object
  ex : MyObjectList:=vDeserializer.Value<TMyObjectListType> //will not work, in read method of the converter the parameter "V" will be nil


Here is the source of a little test project with comments :
Ps : I tried to attach the file but the browser told me I didn't accept these file type (*.pas or * .Zip)

unit wMainFrm;
{
Serializing objects list

- Ngs (NgSerializor) needs to use converters

- for each object list class we need to have an attribut indicating the converter to use

- Different object list class can use the same converter if they deal with objects descendants of the base list using the convertor

- object list cannot be deserialize directly, they must be owned by an object
  ex : MyObjectList:=vDeserializer.Value<TMyObjectListType> will not work, in read method of the converter the parameter "V" will be nil

}

interface

uses
 Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
 Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Buttons,
 system.Generics.Defaults,
 system.Generics.collections,
 NG.Serialization,
 NG.Serialization.Binary, Vcl.StdCtrls;


type
 TMyObjectType = class(Tobject)
 end;

 TwdeMySecondObjectType=Class(TMyObjectType)
 protected
  fvalue1 : Longint;
  fName : String;
  fValue2 : String;
  fValue3 : Word;
 public
  property value1 : Longint read fvalue1 write fvalue1;
  property Name : String read fName write fName;
  property Value2 : String read fValue2 write fValue2;
  property Value3 : Word read fValue3 write fValue3;
 End;

 TwdeObjectsListConverter=Class(TConverter)
  public
   function  GetReadMode: TReadMode; override;
   procedure Write(S: TSerializer; const V); override;
   procedure Read(D: TDeserializer; var V); override;
  end;

 [Converter(TwdeObjectsListConverter)]
 TMyCustomObjectsList<T:TMyObjectType>=Class(TObjectList<T>)
 End;

 TMyObjectsList=TMyCustomObjectsList<TMyObjectType>;

 [Converter(TwdeObjectsListConverter)]
 TmyDescendantObjectsList = Class(TMyCustomObjectsList<TwdeMySecondObjectType>);

 TwdeDictionnary = Class(Tobject)
  fMyItemsList : TmyDescendantObjectsList;
 public
  constructor create;
  destructor Destroy;override;
 End;

  TForm1 = class(TForm)
    Button_Test: TSpeedButton;
    Memo1: TMemo;
    procedure Button_TestClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$Region 'TwdeObjectsListConverter'}
{------------------------------------------------------------------------------}
function TwdeObjectsListConverter.GetReadMode: TReadMode;
 begin
  result:=rmNormal;
 end;
{------------------------------------------------------------------------------}
procedure TwdeObjectsListConverter.Read(D: TDeserializer; var V);
var
 vList : TMyObjectsList;
 vObject: TMyObjectType;
begin
  D.BeginArray;

  vList:=TMyObjectsList(v);
  vList.Clear;

  while D.HasNext do
   begin
    vObject:=D.Value<TMyObjectType>;
    vList.Add(vObject);
   end;

  D.EndArray;
 end;
{------------------------------------------------------------------------------}
procedure TwdeObjectsListConverter.Write(S: TSerializer; const V);
var
 va: Integer;
 vDicoRec: TwdeMySecondObjectType;
 vList: TMyObjectsList;
 vObject: TMyObjectType;
begin
 S.BeginArray('Items');
 vList := TMyObjectsList(v);
 for va := 0 to vList.Count - 1 do
  begin
   vObject:=vList[va];
   vDicoRec:=TwdeMySecondObjectType(vObject);
   S.Value(vObject);
  end;
 S.EndArray;
end;
{------------------------------------------------------------------------------}
{$EndRegion 'TwdeObjectsListConverter'}

{$R *.dfm}
{------------------------------------------------------------------------------}
procedure TForm1.Button_TestClick(Sender: TObject);
var
 vDicoRecord: TwdeMySecondObjectType;
 vStream : TmemoryStream;
 vSerializator : TBinarySerializer;
 vDeserializer : TBinaryDeserializer;
 vDictionnary : TwdeDictionnary;
 va : Longint;

begin
 vDictionnary:=TwdeDictionnary.Create;

 for va:=1 to 100000 do
  begin
   vDicoRecord:=TwdeMySecondObjectType.Create;
   vDicoRecord.Name:='Value_'+IntTostr(va);
   vDicoRecord.fValue2:='Value_'+IntTostr(va);
   vDictionnary.fMyItemsList.Add(vDicoRecord)
  end;

 vStream:=TMemoryStream.Create;
 vSerializator:=TBinarySerializer.Create(vStream);
 vSerializator.Value(vDictionnary);
 vSerializator.FlushBuffer;
 vSerializator.Free;

 vStream.Position:=0;
 vDeserializer:=TBinaryDeserializer.Create(vStream);
 vDictionnary:=vDeserializer.Value<TwdeDictionnary>;

 Memo1.Lines.Add('count : '+IntToStr(vDictionnary.fMyItemsList.Count));
 end;

{------------------------------------------------------------------------------}

{$Region 'TwdeDictionnary'}
{------------------------------------------------------------------------------}
constructor TwdeDictionnary.create;
 begin
  fMyItemsList:=TmyDescendantObjectsList.Create(true);
 end;
{------------------------------------------------------------------------------}
destructor TwdeDictionnary.Destroy;
 begin
  fMyItemsList.Free;
  inherited;
 end;
{------------------------------------------------------------------------------}
{$Region 'TwdeDictionnary'}
end.
zip
zip
wMainFrm.zip
2K

Comments

  • 3 Comments sorted by Votes Date Added
  • Hi,

    1) You again forgot about fill-read mode. Should be like this:

    function TwdeObjectsListConverter.GetReadMode: TReadMode;
    begin
      Result := rmFillRead;
    end;

    2) Object list CAN be deserialized directly; Yes, they still need converters, but you can write a converter, which will create an instance of the list. The parameter V in converter's Read method will be initially set to nil, but its a var parameter, and, in this case, you need to create an instance (and assign it to V). 
    So, this is possible; but, usually - useless, because, usually, collections are owned by some other objects; and moreover, usually, you just not allowed to replace such collections as a whole. Thats why fill-read mode was developed.



  • Thanks for your message - we added a new Wiki entry called
    How to serialize collections to simplify work with TList objects and to provide some background information.

Sign In or Register to comment.