RTTI: как получить значения динамического массива, объявленного как свойство класса

Пожалуйста помогите.

Я искал существующие вопросы и не нашел, как я могу получить все опубликованные свойства элементов (объявленных как Class) в динамическом массиве в классе delphi (я использую Delphi 7 IDE (я не могу использовать другую версию))

У меня есть такой код:

  TObjectList = array of TObject;
  TSubClass = class(TObject)
  private
    FFirstName: string;
    FLastName: string;
    FDOB: TDateTime;
    FArray : TObjectList;
  published
    property FirstName: string read FFirstName write FFirstName;
    property LastName: string read FLastName write FLastName;
    property DOB: TDateTime read FDOB write FDOB;
    property MyArray : TObjectList read FArray write FArray ;
  end;

  TListSubClass = array of TSubClass;

  TPersonList = class(TObject)
  private
    FSubClasses: TListSubClass;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property SubClasses: TListSubClass read FSubClasses write FSubClasses;
  end;

У меня есть ссылка на Элемент класса TPersonList (MyVariable: TPersonList).

Как я могу с помощью RTTI получить данные всех опубликованных свойств моих элементов массива FSubClasses и FArray?

Как я могу установить новые данные в FSubClasses с помощью RTTI?

Спасибо, Сергей.


person Dr. Serg    schedule 06.11.2010    source источник


Ответы (2)


Взгляните на GetDynArrayProp и GetPropList блока TypInfo.

GetDynArrayProp возвращает указатель на базовый массив, затем вы можете привести его к правильному типу массива.

GetPropList возвращает указатель на массив информации о свойствах всех свойств переданного вами класса.

Запись TPropInfo, которую вы получаете обратно от GetPropList, содержит информацию об адресах методов получения и установки, связанных со свойством, вы можете использовать их для вызова средства получения или установки соответственно.

В общем, вам следует глубже взглянуть на модуль TypInfo в справке по Delphi или в онлайн-документации:

http://docwiki.embarcadero.com/VCL/en/TypInfo

person Jens Mühlenhoff    schedule 06.11.2010
comment
Спасибо за ответ, но когда я получаю таким образом элементы массива, почему у них нет информации о классе? Это свойство равно нулю. - person Dr. Serg; 07.11.2010
comment
Что вы имеете в виду, говоря "нет информации о классе", не могли бы вы отредактировать свой вопрос с помощью кода, который вы пробовали до сих пор? - person Jens Mühlenhoff; 07.11.2010
comment
Я имею в виду, что когда я получаю форму массива, элементы GetDynArrayProp не включают информацию classInfo. После моих исследований я нашел решение той части, где мне нужно было получить свойства предмета. GetDynArrayProp - работает, если мой Родитель класса TPersistent. PS Извините за английский - я еще студент ^ _ ^ - person Dr. Serg; 08.11.2010
comment
Если вы хотите использовать RTTI (т.е. информацию о типах опубликованных свойств), родительский класс должен быть объявлен с включенным RTTI (до Delphi 2010). Так обстоит дело с TPersistent, но не с типом TObject. Это можно сделать принудительно, используя условное выражение {$ M +} перед объявлением типа класса и {$ M-} после него. - person Arnaud Bouchez; 08.11.2010
comment
@ Д-р. Serg: Было бы намного проще, если бы вы могли использовать TList или TObjectList или потомок одного из них, как предлагает А.Бушез. Использование указателей гораздо более подвержено ошибкам. Также было бы полезно, если бы вы отредактировали свой вопрос, включив в него свое текущее состояние кода. - person Jens Mühlenhoff; 08.11.2010
comment
Я нашел решение (см. Мой предыдущий комментарий). Думаю, что ваша информация помогла мне начать поиск решения моей проблемы. Я посчитал тебе лучший ответ. - person Dr. Serg; 11.11.2010
comment
Спасибо за помощь в решении :) - person Dr. Serg; 11.11.2010
comment
Рад, что смог помочь, и в этом вся суть Stack Overflow :). - person Jens Mühlenhoff; 11.11.2010

То, что вы называете «динамическим массивом», в мире Delphi не называется «динамическим массивом». «Динамический массив» определяется как MyVar: например, массив целых чисел. В ваших классах есть только потомки TList. Эти потомки TList представляют собой своего рода динамическое хранилище, но оно называется TList (или TObjectList) вместо «динамического массива».

Так что просто используйте модуль TypInfo.

  • GetPropList предоставит вам список всех свойств.
  • Затем вызовите GetObjectProp для каждого элемента PPropInfo, который сопоставляет класс, и получите экземпляр каждого свойства.
  • Вызовите GetStrProp, чтобы получить содержимое опубликованного свойства строки;
  • Вызовите GetOrdProp, чтобы получить содержимое целочисленного опубликованного свойства.
  • Вызовите GetFloatProp, чтобы получить значение с плавающей запятой, например TDateTime.

В случае опубликованного свойства класса после вызова GetObjectProp проверьте возвращаемый тип экземпляра и перечислите его содержимое в соответствии с его классом (TObjectList или TListSubClass).

Это такой метод, который мы используем в нашей ORM с открытым исходным кодом (мы выделили некоторые объектно-ориентированные классы для доступа к свойствам, поэтому нам не нужен модуль typinfo). См. http://synopse.info/fossil/finfo?name=SQLite3/SQLite3Commons.pas

person Arnaud Bouchez    schedule 07.11.2010
comment
На самом деле он не использует TList, посмотрите еще раз на объявления типов, они действительно являются динамическими массивами. - person Jens Mühlenhoff; 07.11.2010
comment
Верно! Поэтому вам просто нужно использовать GetDynArrayProp и привести возвращаемый указатель к вашему типу TObjectList, чтобы получить к нему доступ как к обычному динамическому массиву: для i: = 0 до высокого (TObjectList (aPointer)) do ... TObjectList (aPointer) [0] ... - person Arnaud Bouchez; 07.11.2010
comment
Спасибо за ответ. И как мне сохранить массив в собственность? Потому что, когда я написал SetDynArrayProp (MyVariable, 'SubClasses', PointerToNewArrayWithNewLenght); у меня есть только первый элемент в массиве свойств :( почему? - person Dr. Serg; 08.11.2010
comment
как вам кодировать PointerToNewArrayWithNewLenght? Вы должны использовать указатель (NewArrayVar), а не @NewArrayVar, насколько я могу догадаться. pointer () получит весь указатель на динамический массив, тогда как @ получит указатель на первый элемент массива. Вы можете увидеть разницу, если во время отладки используете Alt-F2 для дизассемблирования сгенерированного кода. - person Arnaud Bouchez; 08.11.2010
comment
Я не использую оператор @. Проблема заключалась в использовании функций Delphi 7. Я сравнил код для последнего Delphi и Delphi 7., скопированный с 2010 года, что мне нужна функция, и она сработала :). То есть я переписал код SetDynArrayProp. :) - person Dr. Serg; 11.11.2010
comment
Спасибо за помощь в решении :) - person Dr. Serg; 11.11.2010