Получите смещение поля в записи Дельфи во времени выполнения

Учитывая тип записи:

TItem = record
   UPC : string[20];
   Price : Currency;
   Cost : Currency;
   ...
end; 

И название поля как строка, как я могу получить смещение того поля в записи? Я должен сделать это во времени выполнения - название поля к доступу решено во времени выполнения.

Пример:

var
   pc : Integer;
   fieldName : string;
   value : Currency;
begin
   pc := Integer(@item);                    // item is defined and filled elsewhere
   fieldName := Text1.Text;                 // user might type 'Cost' or 'Price' etc
   Inc(pc, GetItemFieldOffset(fieldName));  // how do I implement GetItemFieldOffset?
   value := PCurrency(pc)^;
   ..

Я использую Delphi 7.

6
задан Blorgbeard 2 July 2010 в 09:11
поделиться

4 ответа

Вы не можете. Delphi 7 не выдает RTTI для записей. Есть и другие варианты (как видно из предыдущих ответов), но для них требуется ручное сопоставление «Имя поля» -> «Смещение».

8
ответ дан 8 December 2019 в 13:43
поделиться

Следующее будет работать для вашего упрощенного сценария, но я сомневаюсь, что можно будет создать универсальную функцию для такого рода вещей.

Лучшее, что я могу придумать, это добавить какой-то объект регистрации, но для этого все равно потребуется зарегистрировать все записи, от которых требуется смещение.

function GetItemFieldOffset(const Value: string): Integer;
var
  item: TItem;
begin
  if Value = 'UPC' then Result := 0
  else if Value = 'Price' then Result := Integer(@item.Price) - Integer(@item)
  else if Value = 'Cost' then Result :=  Integer(@item.Cost) - Integer(@item)
  else raise Exception.CreateFmt('Unhandled condition (%0:s)', [Value]);
end;
4
ответ дан 8 December 2019 в 13:43
поделиться

Как сказал Алекс, Delphi 7 не испускает RTTI для записей, поэтому вы не можете получить необходимая информация во время выполнения. Однако в более поздних версиях (Delphi 2010+) это так, и следующий код:

TItem = record
   UPC : string[20];
   Price : Currency;
   Cost : Currency;
//...
end;
    var
       rttiContext: TRttiContext;
       rttiType: TRttiType;
       fields: TArray<TRttiField>;
       item: TItem;
    begin
        rttiType := rttiContext.GetType(TypeInfo(TItem));
        caption := rttiType.Name + ' {';
        fields := rttiType.GetFields;
        for i := low(fields) to high(fields) do
        begin
          caption := caption +'{name='+fields[i].Name+',';
          caption := caption +'offset='+IntToStr(fields[i].Offset)+'}';
        end;
        caption := caption + '}';

создаст 'TItem {{name = UPC, offset = 0} {name = Price, offset = 24} {name = Cost, offset = 32}} '

Вы также можете установить значение поля в конкретном экземпляре (хотя вам также следует проверить тип), используя:

if fields[i].Name = 'Price' then
  fields[i].SetValue(@item, 10);
4
ответ дан 8 December 2019 в 13:43
поделиться

Это то, что вы ищете

 type
   TItem = record
     UPC : string[20];
     Price : Currency;
     Cost : Currency;
     ...
   end; 

 var
   myRecord    : TItem ;
   myRecordPtr : ^TItem ;

 begin
   myRecord.price:= 100;
   myRecord.UPC := '111';
   myRecordPtr := @myRecord;
   if edit1.text = 'UPC' then   
     ShowMessage(myRecordptr.UPC);  // Displays '111'
   else if edit1.text = 'price' then   
     ShowMessage(myRecordptr.Price);  // Displays '100'
 end;
1
ответ дан 8 December 2019 в 13:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: