RTTI и сериализация класса

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

RTTI и сериализация класса

Сообщение CynicRus » 26.03.2017 12:55:40

Добрый день господа! Имеется абстрактный класс, с некоторой последовательностью полей. Поля в классе записаны в определенном порядке. Необходимо записать в XML эти поля со значениями, именно в том порядке, в котором они и следуют друг за другом в описании. Чтобы не плодить говнокод, решил сделать прогрессивно, через RTTI:
Код: Выделить всё
procedure TRequestBody.ToXML(const XMLNode: TDomNode);
var
  PropList: TPropInfoList;
  i: integer;
  PI : PPropInfo;
  PT : PTypeInfo;
  xDoc: TXMLDocument;
  RootNode, ParentNode, Node: TDomNode;
begin
  xDoc := TXMLDocument.Create;
  try
    RootNode := xDoc.CreateElement('RequestBody');
    xDoc.AppendChild(RootNode);
    RootNode := xDoc.DocumentElement;
    PropList := TPropInfoList.Create(Self,tkProperties);

  for i := 0 to PropList.Count - 1 do
  begin
     PI := PropList.Items[i];
     PT:=PI^.PropType;
     //Str := Pi^.Name;
    ParentNode := xDoc.CreateElement(Pi^.Name);
    case PT^.Kind of
    tkInteger:
      Node := xDoc.CreateTextNode(IntToStr(GetOrdProp(Self,PI)));
    tkSString,
    tkLString,
    tkAString:
      Node := xDoc.CreateTextNode(GetStrProp(Self,PI));
    tkFloat :
      if (PT=TypeInfo(TDateTime)) then
       Node := xDoc.CreateTextNode(DateTimeToStr(GetFloatProp(Self,PI)));
    end;
    ParentNode.AppendChild(Node);
    RootNode.AppendChild(ParentNode);
    //ParentNode.NodeValue:=;
  end;
  finally
    XMLNode.AppendChild(RootNode.CloneNode(true,XMLNode.OwnerDocument));
    xDoc.Free;
  end;
end;


А на выходе, я получаю совершенно не тот порядок полей. Поля класса сортируются во время компиляции чтоли? Можно ли как-то получить всё же из RTTI порядок полей, как они описаны в классе, без сортировки? Или же придётся городить лесенку типа:
Код: Выделить всё
RootNode := xDoc.DocumentElement;
    ParentNode := xDoc.CreateElement('ProtocolLabel');
    Node := xDoc.CreateTextNode(self.ProtocolLabel);
    ParentNode.AppendChild(Node);
    RootNode.AppendChild(ParentNode);
    ParentNode := xDoc.CreateElement('ProtocolVersion');
    Node := xDoc.CreateTextNode(self.ProtocolVersion);
   RootNode.AppendChild(ParentNode);


Всё таки хотелось бы решить задачу изящно-))
CynicRus
постоялец
 
Сообщения: 106
Зарегистрирован: 28.06.2012 14:31:11

Re: RTTI и сериализация класса

Сообщение vitaly_l » 26.03.2017 13:46:37

CynicRus писал(а):решил сделать прогрессивно, через RTTI: Всё таки хотелось бы решить задачу изящно-))

Попробуйте посмотреть, как сохраняют XML в StringGrid, возможно вам тот вариант больше понравится (последовательность там сохраняется).
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: RTTI и сериализация класса

Сообщение CynicRus » 26.03.2017 14:02:05

vitaly_l писал(а):
CynicRus писал(а):решил сделать прогрессивно, через RTTI: Всё таки хотелось бы решить задачу изящно-))

Попробуйте посмотреть, как сохраняют XML в StringGrid, возможно вам тот вариант больше понравится (последовательность там сохраняется).


Там всё сделано портянками через TXMLConfig, выглядит как код, ради кода. Мне надо-то 5 свойств сохранить, в документ определенной структуры, которую менять нельзя. RTTI выглядит идеально для этих целей, еслибы не сортировка имен полей-(
CynicRus
постоялец
 
Сообщения: 106
Зарегистрирован: 28.06.2012 14:31:11

Re: RTTI и сериализация класса

Сообщение MysticCoder » 26.03.2017 14:40:44

Оптимизация О3 кажись ща меняет порядок полей при необходимости. Попробуй отключить.
Я у себя когда то решал такую задачу примерно так:
1) в конструкторе регистрируем каждое поле типа MyRegisterField(@Field1, 'Field1', Sizeof(Field1)); при этом сохраняется в список адрес и размер поля в байтах
2) когда надо сохранять проходим по списку и сохраняем все данные в сыром виде
3) плюс. Добавление поддержки еще одного поля обходится в +1 строку
4) минус. для некоторых сложных структур типа массивов или указателей придется делать отдельные костыли
MysticCoder
постоялец
 
Сообщения: 154
Зарегистрирован: 14.09.2013 00:20:28

Re: RTTI и сериализация класса

Сообщение zub » 26.03.2017 14:42:52

>>Чтобы не плодить говнокод, решил сделать прогрессивно, через RTTI:
"Прогрессивный" подход в данном случае очень ненадежен - стоит появиться у предка какомунибудь полю - все слетит.

>>Поля класса сортируются во время компиляции чтоли?
ага. какбы намекая на то что нестоит расчитывать на какойто определенный порядок их следования.

Юзайте не класс а record - там "поля" уже не "поля", но следуют в порядке объявления

Добавлено спустя 2 минуты 36 секунд:
>>Оптимизация О3 кажись ща меняет порядок полей при необходимости. Попробуй отключить.
О3 вроде как может меняем физическую последовательность мемберов рекордов-объектов-классов в памяти, поля это всеголишь алиас к "физическим" данным - их порядок вообще не важен
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: RTTI и сериализация класса

Сообщение CynicRus » 26.03.2017 15:04:12

Спасибо, жаль, идея казалась перспективной. В итоге на времянку сделал лесенкой
Код: Выделить всё
ParentNode := xDoc.CreateElement('ProtocolLabel');
Node := xDoc.CreateTextNode(self.ProtocolLabel);
ParentNode.AppendChild(Node);

, рекорды по ряду причин не подойдут. За идею с рекордами - спасибо, как и за идею регистрировать свойства в консрукторе.
CynicRus
постоялец
 
Сообщения: 106
Зарегистрирован: 28.06.2012 14:31:11


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Google [Bot], Yandex [Bot] и гости: 37

Рейтинг@Mail.ru