Тут нужно немного пояснить. Класс будет записывать/читать все свойства, тип которых целый (в том числе логический), перечислимый, вещественный, символьный, строковый, а также некоторые классы, которые поддерживают работу с потоками. Отличить эти классы от других, можно запросив у них интерфейс IStreamPersist, который объявлен в Classes.pas так:
IStreamPersist = interface ['{B8CD12A3-267A-11D4-83DA-00C04F60B2DD}'] procedure LoadFromStream(Stream: TStream); procedure SaveToStream(Stream: TStream); end;Этот класс реализуют, например, все потомки TGraphic, такие как TBitmap, TIcon, TMetafile, а также наш класс TRttiObject.
Почему в качестве предка выбран TInterfacedPersistent, а не TObject или TInterfacedObject. Тут несколько причин: во-первых, он является потомком TPersistent, который объявлен с директивой {$M+} (правда ничего не мешало бы сделать это самим), а во-вторых, в нем наиболее удачно для нас реализованы методы интерфейса IInterface (подсчет ссылок, реализованный в TInterfacedObject, нам ни к чему, а если взять TObject, то эти методы нужно будет реализовать самому).
procedure TRttiObject.SaveToStream(Stream: TStream); var TypeData: PTypeData; PropList: PPropList; Count,i: Integer;Я не буду подробно комментировать каждую функцию из TypInfo.pas, по комментариям сами разберетесь, прошу только обратить внимание на локальную процедуру записи класса. Сначала мы получаем экземпляр самого объекта. Потом проверяем, не является ли он потомком TGraphic. Далее записываем в поток, является ли графический объект пустым. Дело в том, что если объект (например Bitmap) пустой, то вызов SaveToStream не запишет в поток ничего. При чтении объект не сможет узнать о том, что он должен быть пустым, и будет, как ни в чем не бывало читать следующие по очереди данные из потока. Само собой это вызовет ошибку. Честно говоря, мне не очень нравится, как я решил эту проблему. Если у Вас есть идеи получше - пишите в обсуждении статьи.
И в конце процедуры WriteClassProp самое главное. Запрашиваем интерфейс IStreamPersist и заодно проверяем, поддерживает ли вообще его объект. Если да, то вызываем метод интерфейса SaveToStream.
Процесс чтения свойств из потока аналогичен. Я не буду его рассматривать в статье, в прилагаемом примере вы его найдете и сами сможете разобраться.