FPC: RTTI по ​​записям

Я впервые на этом сайте. Обычно у меня нет проблем с поиском ответов в старых сообщениях, но я не могу решить свою настоящую проблему.

Я хотел бы знать, как использовать функции RTTI, чтобы знать во время работы свойства / элементы записи в Lazarus / FPC? Я знаю, как это сделать для класса (потомок Tpersistent и опубликованные свойства), но не для FPC. В некоторых ссылках указано, как это сделать в Delphi (из D2010), но я не знаю, как перенести это в Lazarus.

Заранее благодарим за помощь и содействие. Салим Лархриб.

Кевину: Как я уже сказал, это мое первое требование. Но я понимаю. Ты прав. Это мой код

procedure TMainForm.btRecordTHashListClick(Sender: TObject);
var
  pTData    : PTypeData;
  pTInfo    : PTypeInfo;
  TablePtr  : PatableRecord;
  Loop      : Integer;
begin
  // Set of Record pointers + HashList

  // Create Container
  if  not Assigned(FTableRecList) then FTableRecList := TFPHashList.Create;

  // Insert data
  new(TablePtr);
  TablePtr^.description := 'Dictionnaire des tables.';
  FTableRecList.add('atable', TablePtr );

  new(TablePtr);
  TablePtr^.description := 'Dictionnaire des fonctions.';
  FTableRecList.add('afunction', TablePtr );

  new(TablePtr);
  TablePtr^.description := 'Dictionnaire des listes d''option.';
  FTableRecList.add('alist', TablePtr );

  // Read records
  for Loop:=0 to FTableRecList.Count-1 do
  begin
    TablePtr := FTableRecList[Loop];
    ShowMessage('Parcours Index : ' + TablePtr^.description);
  end;

  // Find records
  try
    TablePtr := FTableRecList.Find('ddafunction');
    ShowMessage('Record finded : ' + TablePtr^.description);
  except
    ShowMessage('Not such record .');
  end;
  try
    TablePtr := FTableRecList.Find('afunction');
    ShowMessage('Record finded : ' + TablePtr^.description);
  except
    ShowMessage('No such record.');
  end;

  // Free memory : To put later in TFPHashList wrapper
  for Loop:=0 to FTableRecList.Count-1 do Dispose(PatableRecord(FTableRecList[Loop]));

// RTTI
  pTInfo := TypeInfo(TatableRecord);

  pTData := GetTypeData(pTInfo);
  ShowMessage('Member count = '+IntToStr(pTData^.PropCount));
end;

person Salim Larhrib    schedule 06.01.2015    source источник
comment
Free Pascal должен иметь неплохую совместимость с Delphi после того, как вы включите соответствующий режим компилятора . Итак, следующий ответ может быть полезным stackoverflow.com/a/23824290/2626313 (я использовал Google: site:stackoverflow.com delphi rtti record, чтобы найти его)   -  person xmojmr    schedule 06.01.2015


Ответы (1)


ВНИМАНИЕ! Он работает с FPC 2.7.1 или более поздней версии.

Вы можете работать с полями записей, используя указатели. Вот пример:

program rttitest;

uses
    TypInfo;

type
    TMyRec = record
        p1: Integer;
        p2: string;
    end;

var
    td: PTypeData;
    ti: PTypeInfo;
    mf: PManagedField;
    p: Pointer;
    f: Pointer;

    r: TMyRec;

begin
    r.p1 := 312;
    r.p2 := 'foo-bar';

    ti := TypeInfo(r);
    td := GetTypeData(ti);

    Writeln(td^.ManagedFldCount); // Get count of record fields

    // After ManagedFldCount TTypeData contains list of the TManagedField records
    // So ...
    p := @(td^.ManagedFldCount); // Point to the ManagedFldCount ...
    // Inc(p, SizeOf(Integer)); // Skip it (Wrong for 64-bit targets)
    // Next line works for both
    Inc(p, SizeOf(td^.ManagedFldCount)); // Skip it

    mf := p; // And now in the mf we have data about first record's field
    Writeln(mf^.TypeRef^.Name);

    Write(r.p1); // Current value
    f := @r;
    Inc(f, mf^.FldOffset); // Point to the first field
    Integer(f^) := 645; // Set field value
    Writeln(r.p1); // New value

    // Repeat for the second field
    Inc(p, SizeOf(TManagedField));
    mf := p;
    Writeln(mf^.TypeRef^.Name);

    Write(r.p2);
    f := @r;
    Inc(f, mf^.FldOffset);
    string(f^) := 'abrakadabra';
    Writeln(r.p2);


    Readln;
end.
person Abelisto    schedule 07.01.2015
comment
ideone.com поддерживает язык Pascal (fpc) (fpc 2.6.2), но ваш фрагмент не компилируется там как есть из-за Error: Identifier not found "PManagedField". Можете ли вы создать исполняемое доказательство того, что ваш код работает? - person xmojmr; 07.01.2015
comment
@xmojmr Да. Прости. Это просто потому, что я сейчас использую последнюю версию svn-транка FPC (3.1.1). И последняя стабильная версия FPC (2.6.4) по-прежнему не включает эту функцию. - person Abelisto; 07.01.2015
comment
Использую fpc 2.6.4. Я обновлю его и вернусь. В любом случае спасибо за помощь. - person Salim Larhrib; 07.01.2015
comment
Очень хорошо работает с fpc 3.1.1. Есть ли способ получить название свойства ?? Поскольку mf ^ .TypeRef ^ .Name дает имя типа. - person Salim Larhrib; 07.01.2015
comment
@SalimLarhrib Как я могу видеть в исходном коде typinfo - нет, просто потому, что имена полей записи не хранятся нигде в данных RTTI. Поэтому, если вам нужно работать с полями по имени, вы должны использовать классы вместо записей. - person Abelisto; 07.01.2015
comment
Я использую Free Pascal Compiler версии 3.1.1 [2015/11/25] для x86_64, и программа вылетает в Writeln (mf ^ .TypeRef ^ .Name); ¿Что могло быть? - person Luciano Lorenti; 25.11.2015
comment
@LucianoLorenti Исправляю код. Ошибка была в строке Inc(p, SizeOf(Integer)); // Skip it, просто измените ее на Inc(p, SizeOf(td^.ManagedFldCount)); Удачи. - person Abelisto; 25.11.2015