可以按名称更新 TRecord 成员
Possible to update TRecord member by name
当你有记录成员的名称时,是否可以为TMyRecord 获取和设置值?类似于 RTTI
.
我不能使用数组,因为成员可能有不同的数据类型。
类型
TMyRecord = record
X: Integer;
Y: Integer;
Z: DateTime;
end;
var MyRecord: TMyRecord;
procedure UpdateValue(aRecordMemberName: string; AValue: Integer);
begin
MyRecord[aRecordmemberName] := AValue;
end;
function GetValue(aRecordMemberName: string): Integer;
begin
Result := MyRecord[aRecordmemberName];
end;
procedure Main();
begin
SetValue('X', 5);
showmessage( GetValue('Y').ToString );
end;
另外请注意,是否可以遍历 Record
的所有成员,类似于遍历 TFields
或 TFieldDefs
?
谢谢。
- 在 Firemonkey 中使用 Delphi11
如果您有固定数量的不同类型的字段,您需要通过字符串名称访问这些字段,这有点奇怪。不过,让我们假设这是正确的做法。
RTTI 有点复杂(意味着你需要写“很多”行代码)而且很慢。当然,在您的情况下它可能足够快,所以它可能足够好。但这并不理想。
根据我的经验,人们往往太急于求助于 RTTI。在大多数情况下,有更好的解决方案。
一个 non-RTTI 解决方案是使用 TDictionary<string, Variant>
.
另一个是这样的:
type
EFrogException = class(Exception);
TFrogProperty = (fpName, fpBirthDate, fpWeight);
TFrogPropertyHelper = record helper for TFrogProperty
strict private
const PropNames: array[TFrogProperty] of string = ('Name', 'Birth date', 'Weight');
public
function ToString: string;
class function FromString(const APropName: string): TFrogProperty; static;
end;
TFrog = record
strict private
FProperties: array[TFrogProperty] of Variant;
private
function GetProp(Prop: TFrogProperty): Variant;
procedure SetProp(Prop: TFrogProperty; const Value: Variant);
function GetPropByName(APropName: string): Variant;
procedure SetPropByName(APropName: string; const Value: Variant);
public
property Prop[Prop: TFrogProperty]: Variant read GetProp write SetProp;
property PropByName[Prop: string]: Variant read GetPropByName write SetPropByName; default;
end;
哪里
{ TFrogPropertyHelper }
class function TFrogPropertyHelper.FromString(
const APropName: string): TFrogProperty;
begin
for var Prop := Low(TFrogProperty) to High(TFrogProperty) do
if SameText(Prop.ToString, APropName) then
Exit(Prop);
raise EFrogException.CreateFmt('Invalid frog property: "%s".', [APropName]);
end;
function TFrogPropertyHelper.ToString: string;
begin
if InRange(Ord(Self), Ord(Low(TFrogProperty)), Ord(High(TFrogProperty))) then
Result := PropNames[Self]
else
Result := '';
end;
{ TFrog }
function TFrog.GetProp(Prop: TFrogProperty): Variant;
begin
Result := FProperties[Prop];
end;
function TFrog.GetPropByName(APropName: string): Variant;
begin
Result := Prop[TFrogProperty.FromString(APropName)];
end;
procedure TFrog.SetProp(Prop: TFrogProperty; const Value: Variant);
begin
FProperties[Prop] := Value;
end;
procedure TFrog.SetPropByName(APropName: string; const Value: Variant);
begin
Prop[TFrogProperty.FromString(APropName)] := Value;
end;
那么你可以这样做:
procedure TForm1.FormCreate(Sender: TObject);
begin
var James: TFrog;
James['Name'] := 'James';
James['Birth date'] := EncodeDate(2016, 05, 10);
James['Weight'] := 2.4;
ShowMessage(James['Name']);
James['Name'] := 'Sir James';
ShowMessage(James['Name']);
// And you can still be type safe if you want to:
James.Prop[fpName] := 'Sir James Doe';
ShowMessage(James.Prop[fpName]);
end;
当你有记录成员的名称时,是否可以为TMyRecord 获取和设置值?类似于 RTTI
.
我不能使用数组,因为成员可能有不同的数据类型。
类型
TMyRecord = record
X: Integer;
Y: Integer;
Z: DateTime;
end;
var MyRecord: TMyRecord;
procedure UpdateValue(aRecordMemberName: string; AValue: Integer);
begin
MyRecord[aRecordmemberName] := AValue;
end;
function GetValue(aRecordMemberName: string): Integer;
begin
Result := MyRecord[aRecordmemberName];
end;
procedure Main();
begin
SetValue('X', 5);
showmessage( GetValue('Y').ToString );
end;
另外请注意,是否可以遍历 Record
的所有成员,类似于遍历 TFields
或 TFieldDefs
?
谢谢。
- 在 Firemonkey 中使用 Delphi11
如果您有固定数量的不同类型的字段,您需要通过字符串名称访问这些字段,这有点奇怪。不过,让我们假设这是正确的做法。
RTTI 有点复杂(意味着你需要写“很多”行代码)而且很慢。当然,在您的情况下它可能足够快,所以它可能足够好。但这并不理想。
根据我的经验,人们往往太急于求助于 RTTI。在大多数情况下,有更好的解决方案。
一个 non-RTTI 解决方案是使用 TDictionary<string, Variant>
.
另一个是这样的:
type
EFrogException = class(Exception);
TFrogProperty = (fpName, fpBirthDate, fpWeight);
TFrogPropertyHelper = record helper for TFrogProperty
strict private
const PropNames: array[TFrogProperty] of string = ('Name', 'Birth date', 'Weight');
public
function ToString: string;
class function FromString(const APropName: string): TFrogProperty; static;
end;
TFrog = record
strict private
FProperties: array[TFrogProperty] of Variant;
private
function GetProp(Prop: TFrogProperty): Variant;
procedure SetProp(Prop: TFrogProperty; const Value: Variant);
function GetPropByName(APropName: string): Variant;
procedure SetPropByName(APropName: string; const Value: Variant);
public
property Prop[Prop: TFrogProperty]: Variant read GetProp write SetProp;
property PropByName[Prop: string]: Variant read GetPropByName write SetPropByName; default;
end;
哪里
{ TFrogPropertyHelper }
class function TFrogPropertyHelper.FromString(
const APropName: string): TFrogProperty;
begin
for var Prop := Low(TFrogProperty) to High(TFrogProperty) do
if SameText(Prop.ToString, APropName) then
Exit(Prop);
raise EFrogException.CreateFmt('Invalid frog property: "%s".', [APropName]);
end;
function TFrogPropertyHelper.ToString: string;
begin
if InRange(Ord(Self), Ord(Low(TFrogProperty)), Ord(High(TFrogProperty))) then
Result := PropNames[Self]
else
Result := '';
end;
{ TFrog }
function TFrog.GetProp(Prop: TFrogProperty): Variant;
begin
Result := FProperties[Prop];
end;
function TFrog.GetPropByName(APropName: string): Variant;
begin
Result := Prop[TFrogProperty.FromString(APropName)];
end;
procedure TFrog.SetProp(Prop: TFrogProperty; const Value: Variant);
begin
FProperties[Prop] := Value;
end;
procedure TFrog.SetPropByName(APropName: string; const Value: Variant);
begin
Prop[TFrogProperty.FromString(APropName)] := Value;
end;
那么你可以这样做:
procedure TForm1.FormCreate(Sender: TObject);
begin
var James: TFrog;
James['Name'] := 'James';
James['Birth date'] := EncodeDate(2016, 05, 10);
James['Weight'] := 2.4;
ShowMessage(James['Name']);
James['Name'] := 'Sir James';
ShowMessage(James['Name']);
// And you can still be type safe if you want to:
James.Prop[fpName] := 'Sir James Doe';
ShowMessage(James.Prop[fpName]);
end;