Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2011.03.06;
Скачать: [xml.tar.bz2];

Вниз

Очередной велосипед   Найти похожие ветки 

 
VLK32   (2010-11-27 17:02) [0]

Т.е. сериализация. Для меня основной вопрос в этом деле - Как сохранять ссылки? Если диаграмма объектов (т.е. во время исполнения) довольно сложная с кучей перекрестных ссылок то как это все дело выгружать/загружать. Я тут подумал и реализовал такую методу.

В базовом классе TClass32 (от которого порождаются все ост.классы кот. мы хотим сериализовать) есть имя экземпляра. В рамках  заданного класса оно уникально. И есть спец. класс TClassPool который в списке хранит привязки ИмяОбъекта - АдресОбъекта.

При создании экземпляра TClass32 автоматически инфа добавляется в пул. Ну и стандартно базовый класс и все остальные поддерживают Load/Save в поток.

Сериализация выглядит вот так:

function GlobalSave(const C:array of TClassPool; const P:Pointer):Boolean;
 var i : Integer;
 begin
  Result := False;
  try                
   if (Length(C)=0) or (P=Nil) then Exit;
   TMem32(P).Save(Length(C));
   for i:=0 to High(C) do C[i].SaveName(P);
   for i:=0 to High(C) do C[i].SaveData(P);
   Result := True;
  except
   // do nothing
  end;
 end;

function GlobalLoad(const C:array of TClassPool; const P:Pointer):Boolean;
 var i : Integer;
 begin
  Result := False;
  try
   if (Length(C)=0) or (P=Nil) then Exit;
   TMem32(P).Load(i);
   if i<>Length(C) then Exit;
   for i:=0 to High(C) do C[i].LoadName(P);
   for i:=0 to High(C) do C[i].LoadData(P);
   Result := True;
  except
   // do nothing
  end;
 end;

где P это указатель на поток.

При выгрузке. Сначала все сериализуемые пулы выгружают в поток имена своих классов и имена экземпляров. Потом пулы выгружают данные экземпляров используя метод Load последних.

При загрузке. Сначала все указанные пулы считывают имена экземпляров и создают их без загрузки внутренних данных. Примерно такой код:

function TClassPool.LoadName(const P:Pointer):Boolean;
 var i,n : Integer;
     S : String;
 begin
  Result := False;
  if P=Nil then Exit;
  try
   TMem32(P).Load(S);
   if AnsiUpperCase(S)<>AnsiUpperCase(FClass.ClassName) then raise Exception.Create("Incorrect Class Name");
   TMem32(P).Load(n);
   for i:=0 to n-1 do
    begin
     TMem32(P).Load(S);
     FClass.Create(S,Self);
    end;
   Result := True;
  except
   // do nothing
  end;
 end;

После этого все экземпляры всех пулов созданы, т.е. уже сущ. в оперативной памяти и во всех пулах иниц. привязка имен к адресам.

Дальше после for i:=0 to High(C) do C[i].LoadData(P); объекты грузят свои данные. А так как в поток вместо ссылок они записывали имена объектов то теперь они могут точно восстановить все свои ссылки запрашивая инфу из пулов.

В программе загрузка и выгрузка выглядит так:

M := TMem32.Create;
GlobalSave([TPlayer.Pool,TGroup.Pool],M);
M.SaveToFile(GetCurrentDir+"\local.dat");
M.Free;

M := TMem32.Create;
M.LoadFromFile(GetCurrentDir+"\local.dat");
GlobalLoad([TPlayer.Pool,TGroup.Pool],M);
M.Free;

Основная нагрузка на кодера ложится в программировании методов Save и Load, но надстройка  сериализации как видите довольно проста. Это хранилища инфы об экземплярах (запись и удаление инфы происходит автоматом и реализована в базовом классе) и две функции.

Прошу высказывать свои мнения по данной методе.


 
VLK32   (2010-11-27 17:09) [1]

Забыл добавить. TClassPool может быть пулом для любого класса порожденного от базового TClass32.


 
VLK32   (2010-11-27 17:20) [2]

Ну и сам   TClass32 = class(TObject)

  protected

   function  GetDataSize:Integer; virtual;
   function  GetMark:Integer; virtual;
   function  GetName:String; virtual;
   function  GetOwner:Pointer; virtual;
   procedure SetMark(const Value:Integer); virtual;
   procedure SetOwner(const Value:Pointer); virtual;
   procedure SetName(const Value:String); virtual;

  public

   function Clear:Boolean; virtual; abstract;
   function Copy(const P:Pointer):Boolean; virtual; abstract;
   function Save(const P:Pointer):Boolean; virtual; abstract;
   function Load(const P:Pointer):Boolean; virtual; abstract;

   constructor Create(const ObjectName:String=""; const Pool:TClassPool=Nil); virtual;

   property Owner : Pointer    read GetOwner   write SetOwner;
   property Mark : Integer     read GetMark    write SetMark;
   property Name : String      read GetName    write SetName;
   property DataSize : Integer read GetDataSize;

 end;

Как видим ни одного дополнительного байта по сравнению с TObject


 
Kerk ©   (2010-11-27 17:45) [3]

Ну так варианта только два. Либо вместо ссылок хранить тестовые идентификаторы, либо вместо ссылок на объект в памяти хранить ссылки на описание объекта в файле. А который из них лучше нужно конкретно по задаче смотреть.


 
VLK32   (2010-11-27 17:54) [4]

На самом деле вариант один - хранить имена. Исходя из этого я и сделал надстройку сериализации в виде объектов-пулов хранящих привязки имен объектов к адресам. Да это дополнительная память но ее нужно не так много. Кроме того сразу доступна базовая функциональность по управлению экземплярами во время исполнения. Очень удобно получать ссылку на объект по его имени в любой момент когда это понадобиться.

Хочу также заметить что порядок выгрузки/загрузки у меня произволен. Т.е. не имеет значения реальная последовательность создания экземпляров во время исполнения.



Страницы: 1 вся ветка

Форум: "Прочее";
Текущий архив: 2011.03.06;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.47 MB
Время: 0.002 c
15-1290424828
stas
2010-11-22 14:20
2011.03.06
Хорошая книга по XCode


11-1228743914
Евгений
2008-12-08 16:45
2011.03.06
delphi7 + rip sysdcu, variants?


3-1253703164
ganda
2009-09-23 14:52
2011.03.06
Хранимые процедуры и внешние файлы


13-1126779474
_Alexander_
2005-09-15 14:17
2011.03.06
EhLib: DBGridEh ругается на отстутсвие gstNone


15-1290500287
ixen
2010-11-23 11:18
2011.03.06
Странная проверка пароля в Firebird





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский