Форум: "Прочее";
Текущий архив: 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.003 c