Сериализатор получает на вход объект и источник/приёмник данных. Задача проста - записать/считать объект. Проблема заключается в том, что Делфи не поддерживает "отражения", с помощью которого можно запросить у рантайма стуртуру объекта, и в соответствии с этой информацией записать/восстановить объект (если быть точным, то граф объектов).
Решил я её довольно простым образом - объявил интерфейс ISerializable, в котором есть 2 метода - для сохранения и для восстановления объекта из контекста. Как вариант, я конечно мог бы объявить некий базовый класс с парой абстрактных методов, но тогда я потерял бы гибкость, ведь не все объекты (в рамках задачи) можно корректно унаследовать от жестко зафиксированного класса.
Сериализатор ISerializer создаётся поверх обыкновенного TStream-а, и позволяет писать/читать в него объекты, строки (string) и двоичные блоки данных. Несложно расширить его для записи стандартных типов - integer, boolean, double и т.д. Для объектов необходимым условием является поддеоржка интерфейса ISerializable.
Алгоритм сериализатора прост. В соответствии с каждым объектом (корректнее сказать - ссылкой) мы ставим ID (фактически порядковый номер). Он сохраняет эти пары значений, и если выясняется, что такой объект мы уже писали в поток, то мы его элементарно пропускаем, оставляя, однако, в потоке ID объекта.
Десериализация (восстановление) аналогична. Вызываем Deserialize только для тех объектов, которые ещё небыли проинициализированны, иначе - возвращаем известную ссылку.
Кое какие тонкости. Для того, чтобы встроить поддержку ISerializable в объект нужно в качестве предка брать TInterfacedObject, или ему подобного. В противном случае, в классе придется писать реализацию интерфейса IInterface с его _AddRef и _Release методами. Т.к. сериализатор работает через интерфейс, в Делфи возникает проблема с подсчётом ссылок, потому в конструкторе стоит вызвать _AddRef (показано в примерах), иначе сериализованный объект будет уничтожен после его записи :). При восстановлении сериализатор НЕ вызывает конструктор, вместо этого он вызывает класс-процедуру NewInstance (после чего спрашивает у полученной ссылки интерфейс ISerializable) именно для этого ему необходимо знать класс.