在运行时获取delphi记录中字段的偏移量

时间:2010-07-02 08:44:40

标签: delphi pointers struct delphi-7 rtti

给出记录类型:

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.

4 个答案:

答案 0 :(得分:8)

你做不到。 Delphi 7不会为记录发出RTTI。还有其他选项(如前面的答案所示),但那些需要手动映射“字段名称” - > “偏移”。

答案 1 :(得分:4)

以下内容适用于您的简化方案,但我怀疑是否可以为这类内容制作通用函数。

我能想到的最好的方法是添加某种注册对象,但仍然需要注册所有需要偏移的记录。

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;

答案 2 :(得分:4)

正如alex所说,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);

答案 3 :(得分:1)

这就是你要找的东西

 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;