Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Ошибки RTTI в Delphi: как правильно обращаться с вложенными записями в рекурсивных обходах

Delphi , Компоненты и Классы , RTTI

Разработчики, работающие с Delphi, часто сталкиваются с необходимостью рекурсивного обхода структур данных. Одним из способов реализации такой функциональности является использование RTTI (Runtime Type Information). Однако, при работе с вложенными записями могут возникать ошибки, связанные с неправильной передачей указателей.

Описание проблемы

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

Анализ кода

В коде процедуры WriteFields присутствует логическая ошибка: при рекурсивном вызове процедуры для вложенной записи Info передается указатель на внешнюю структуру Test, а не на вложенную запись Info.

Подтвержденный ответ

Чтобы исправить ошибку, необходимо корректно передавать указатель на вложенную запись Info в рекурсивный вызов. Для этого следует использовать указатель на начало структуры Test с добавлением смещения, соответствующего началу вложенной записи Info.

Исправленный код

procedure WriteFields(const RType: TRttiType; const Instance: Pointer);
var
  RField: TRTTIField;
  Val: TValue;
begin
  for RField in RType.GetFields do
  begin
    if RField.FieldType.TypeKind <> tkRecord then
    begin
      Val := RField.GetValue(Instance);
      WriteLn(Format('Field Name: %s, Type: %s, Value: %s, Offset: %d', [
        RField.Name,
        RField.FieldType.ToString,
        Val.ToString,
        RField.Offset
      ]));
    end
    else
    begin
      WriteLn(Format('------- Inner record : %s, Offset: %d', [RField.Name, RField.Offset]));
      // рекурсивный вызов процедуры для вложенных полей
      WriteFields(RField.FieldType, PByte(Instance) + RField.Offset);
      WriteLn('-------');
    end;
  end;
end;

...

var
  Test: TTestRecord;
begin
  // установка значений для структуры
  Test.Name := 'Fred';
  Test.Text := 'Some random text';
  Test.Info.Age := 50;

  // вызов процедуры для структуры Test
  WriteFields(TypeInfo(TTestRecord), @Test);
end;

Альтернативный подход

Также можно использовать тип Untyped const для передачи указателя, что позволит корректно обращаться с вложенными записями:

procedure WriteFields(const RType: TRttiType; const Instance);
var
  RField: TRTTIField;
  Val: TValue;
begin
  for RField in RType.GetFields do
  begin
    if RField.FieldType.TypeKind <> tkRecord then
    begin
      Val := RField.GetValue(@Instance);
      // остальной код
    end
    else
    begin
      // остальной код для вложенных записей
      WriteFields(RField.FieldType, (PByte(@Instance) + RField.Offset)^);
    end;
  end;
end;

Вывод

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

Создано по материалам из источника по ссылке.

Разработчики Delphi столкнулись с проблемой неправильной работы RTTI при рекурсивном обходе вложенных записей, что приводило к ошибкам в выводе данных.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: RTTI ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-02-11 00:07:40/0.001248836517334/0