В свою очередь, те компоненты тоже будут опрошены, и т. д. В аргумент Root передаётся ссылка на компонент, для которого когда-то был запущен метод TStream.WriteComponent, и если мы пришли к сериализации данного компонента через один или несколько «каскадов», Root<>Self.

В GetChildren от программиста требуется, чтобы он один или несколько раз вызвал Proc, указывая в качестве аргумента те компоненты , которые нужно сериализовать вместе с данным. Например, в классах TForm и TDataModule в GetChildren организуется цикл по элементам массива TComponent.Components:

var I: Integer; OwnedComponent: TComponent; begin inherited GetChildren(Proc, Root); if Root = Self then for I := 0 to ComponentCount - 1 do begin OwnedComponent := Components[I]; if not OwnedComponent.HasParent then Proc(OwnedComponent); end; end;

В методе же TCustomActionList.GetChildren имеется цикл по Action’ам, которые входят в данный ActionList.

Как выглядит результат работы GetChildren в dfm-формате, мы уже видели: объект сохраняется как бы «внутри» того, который отвечает за его сериализацию. Так, на представленном выше фрагменте dfm-файла, Form1 отвечает за сериализацию Button1, Button2 и ActionList1, а ActionList1 – за сериализацию Action1 и Action2.

Во время же загрузки из потока компонент может узнать о том, кто отвечал за его сериализацию, и предпринять соответствующие действия. Для этого надо переопределить метод

procedure SetParentComponent(Value: TComponent); dynamic;

Например, TAction таким образом при десериализации может зарегистрировать себя в сериализовавшем его ActionList’е. Какой класс выбрать в качестве базового

При проектировании классов бизнес-логики часто возникает очень важный вопрос: какой класс выбрать в качестве базового для того или иного класса? Мы рассмотрели ряд классов, с которыми работает механизм сериализации, но их обилие не должно сбивать нас с толку. Думаю, что вышесказанного уже достаточно, чтобы сделать оптимальный выбор. Для удобства нарисуйте диаграмму классов и отобразите кратность связей между их объектами.

Для класса корневого объекта у нас выбора нет – это должен быть наследник TComponent.

Если требуется, чтобы на объект некоторого класса ссылались сразу несколько объектов – выбора тоже нет, этот класс должен наследоваться от TComponent. Владеть экземплярами такого класса будет, разумеется, корневой объект, а вот насчёт того, кто будет ответственным за сериализацию – стоит подумать. Класс объекта, ответственного за сериализацию, тоже должен быть наследником TComponent.

С оставшимися классами мы поступаем так: для связей типа «один к одному» выбираем TPersistent, в случае же связей типа «один ко многим» создается свойство, тип которого должен быть наследником класса TCollection, а классы элементов коллекции нужно унаследовать от TCollectionItem. Регистрация класса в потоковой системе

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

Перед началом десериализации каждый класс объектов, которые будут восстанавливаться из потока, должен быть зарегистрирован в потоковой системе.

Сделать это просто: для этого нужно лишь воспользоваться процедурами из модуля Classes

{для одного класса} procedure RegisterClass(AClass: TPersistentClass); {сразу для нескольких классов} procedure RegisterClasses(AClasses: array of TPersistentClass);

Где:

type TPersistentClass = class of TPersistent;

В качестве аргумента мы передаём регистрируемый класс или массив регистрируемых классов. Регистрировать нужно действительно все классы, участвующие в сериализации, а не только корневой. Если этого не сделать, при десериализации возникнет исключение с сообщением “Class not found”.

<<< 0 1 2 3 4 5 6 7 8 >>>
Хостинг от uCoz