Получить смещение поля в записи delphi во время выполнения
учитывая тип записи:
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 ответов
ты не можешь. Delphi 7 не испускает RTTI для записей. Есть и другие варианты (как видно из предыдущих ответов), но они требуют ручного сопоставления "имя поля" -> "смещение".
следующее будет работать для вашего упрощенного сценария, но я сомневаюсь, что можно будет сделать общую функцию для такого рода вещей.
лучшее, что я могу подумать, если добавить какой-то объект регистрации, но все равно потребуется зарегистрироваться все записи, которые необходимо смещение.
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;
Как сказал Алекс, 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);
это то, что вы ищете
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;