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

在运行时获取delphi记录中字段的偏移量,delphi,pointers,struct,delphi-7,rtti,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(@ite

给定记录类型:

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)^;
   ..

我用的是Delphi7

这就是你要找的吗

 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;

以下内容适用于您的简化场景,但我怀疑是否有可能为这类事情创建一个通用函数

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

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;

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

正如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 + '}';

不,我有一个类似“UPC”的字符串。我想使用反射或delphi等效程序来获取字符串名称所在字段的值。字符串可以是“UPC”,也可以是“Price”或其他任何内容-我要到运行时才能知道。我希望我理解错了。但是ShowMessage(myRecordptr.Price)将显示100。所以你需要的是用price替换UPC,但我不能在运行时这么做。我遇到这样一种情况,用户将在文本框中键入“Price”或“UPC”或其他内容,然后我必须显示该字段的值(简化的场景);您正在指定成本。您的意思是,在运行时正确之前,您不知道在此指定成本还是价格。换言之,RTTI可以自动、通用地为所有类型的用户提供您可以为自己提供的专门、最有效的服务。@joe是的,我知道它的味道。。我并没有把一个文本框绑在这上面;这只是我能想到的最简单的例子来说明这个问题。它实际上是一种规则引擎的一部分,它执行可以按名称引用数据库字段的命令。问题是,在执行此代码时,相关字段已经加载到记录中。最后,我使用了手动维护的if-else,完全删除了指针,只将
name:string
映射到
value:currency
if fields[i].Name = 'Price' then
  fields[i].SetValue(@item, 10);