gpt4 book ai didi

delphi - 有没有办法在知道字段名称和值的情况下更新记录中的字段

转载 作者:行者123 更新时间:2023-12-03 14:34:39 29 4
gpt4 key购买 nike

给定记录:

MyRecord = record
Company: string;
Address: string;
NumberOfEmplyees: integer;

你能写一个函数调用吗

function UpdateField(var FieldName: string; FieldValue: variant): bool;

这样:

UpdateField('Company', 'ABC Co');

会将 MyRecord.Company 更新为“ABC Co”吗?

我寻找了一个示例,但我找到的所有内容都是针对数据库的。感谢任何为我指明正确方向的帮助。

谢谢,查尔斯

最佳答案

Delphi 7 RTTI 知道并且可以从 TypeInfo(aRecordType) 检索的是:

  • 记录类型名称;
  • 全局规模创纪录;
  • 记录中每个引用计数变量的偏移量和类型(字符串/变量/宽字符串/动态数组/包含引用计数变量的其他嵌套记录)。

在运行时,需要最新信息来释放记录内每个引用计数变量使用的内存,或复制记录内容。记录的初始化也可以在编译器生成的代码中执行(如果记录是在堆栈上创建的),可以通过 _InitializeRecord() 方法执行,也可以在类或实例化了一个动态数组。

在所有版本的 Delphi 中,recordobject 类型都是相同的。

您可以注意到有一个 bug in modern version of Delphi (至少包括 Delphi 2009 和 2010),有时不会创建用于初始化堆栈上对象的代码。您必须使用 record 来代替,但这会破坏与以前版本的 Delphi 的兼容性。 :(

以下是用于存储此 RTTI 数据的结构:

type
TFieldInfo = packed record
TypeInfo: ^PDynArrayTypeInfo; // information of the reference-counted type
Offset: Cardinal; // offset of the reference-counted type in the record
end;
TFieldTable = packed record
Kind: byte;
Name: string[0]; // you should use Name[0] to retrieve offset of Size field
Size: cardinal; // global size of the record = sizeof(aRecord)
Count: integer; // number of reference-counted field info
Fields: array[0..0] of TFieldInfo; // array of reference-counted field info
end;
PFieldTable = ^TFieldTable;

使用这些数据,您可以执行以下操作:

例如,以下是如何使用此 RTTI 比较相同类型的两个记录:

/// check equality of two records by content
// - will handle packed records, with binaries (byte, word, integer...) and
// string types properties
// - will use binary-level comparison: it could fail to match two floating-point
// values because of rounding issues (Currency won't have this problem)
function RecordEquals(const RecA, RecB; TypeInfo: pointer): boolean;
var FieldTable: PFieldTable absolute TypeInfo;
F: integer;
Field: ^TFieldInfo;
Diff: cardinal;
A, B: PAnsiChar;
begin
A := @RecA;
B := @RecB;
if A=B then begin // both nil or same pointer
result := true;
exit;
end;
result := false;
if FieldTable^.Kind<>tkRecord then
exit; // raise Exception.CreateFmt('%s is not a record',[Typ^.Name]);
inc(PtrUInt(FieldTable),ord(FieldTable^.Name[0]));
Field := @FieldTable^.Fields[0];
Diff := 0;
for F := 1 to FieldTable^.Count do begin
Diff := Field^.Offset-Diff;
if Diff<>0 then begin
if not CompareMem(A,B,Diff) then
exit; // binary block not equal
inc(A,Diff);
inc(B,Diff);
end;
case Field^.TypeInfo^^.Kind of
tkLString:
if PAnsiString(A)^<>PAnsiString(B)^ then
exit;
tkWString:
if PWideString(A)^<>PWideString(B)^ then
exit;
{$ifdef UNICODE}
tkUString:
if PUnicodeString(A)^<>PUnicodeString(B)^ then
exit;
{$endif}
else exit; // kind of field not handled
end;
Diff := sizeof(PtrUInt); // size of tkLString+tkWString+tkUString in record
inc(A,Diff);
inc(B,Diff);
inc(Diff,Field^.Offset);
inc(Field);
end;
if CompareMem(A,B,FieldTable.Size-Diff) then
result := true;
end;

因此,出于您的目的,Delphi 7 RTTI 可以在运行时让您知道记录中每个字符串的位置。使用上面的代码,您可以轻松地使用字段索引创建一个函数:

     procedure UpdateStringField(StringFieldIndex: integer; const FieldValue: string);

但您根本没有实现您的请求所需的信息:

  • 字段名称不存储在 RTTI 中(仅存储全局记录类型名称,甚至不总是 AFAIK);
  • 只有引用计数字段才有偏移量,其他简单类型字段(例如整数/ double ......)没有。

如果你确实需要这个功能,Delphi 7下唯一的解决方案是不使用记录,而是使用类。

在 Delphi 7 上,如果您创建一个包含已发布字段的类,您将拥有所有已发布字段所需的所有信息。然后您可以更新此类已发布的字段内容。这就是 VCL 运行时将 .dfm 内容反序列化到类实例中或使用 ORM approach 时执行的操作。 .

关于delphi - 有没有办法在知道字段名称和值的情况下更新记录中的字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6446475/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com