可以按名称更新 TRecord 成员

发布于 2025-01-09 13:18:21 字数 705 浏览 1 评论 0原文

当您拥有记录成员的名称时,是否可以获取和设置 TMyRecord 的值?类似于RTTI

我无法使用数组,因为成员可能具有不同的数据类型。

type

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 的所有成员,类似于迭代 TFieldsTFieldDefs

谢谢。

  • 在 Firemonkey 中使用 Delphi 11

Is it possible to have a get and set value for TMyRecord when you have the name of the record member? something similar to RTTI.

I cannot use an array as the members may have different data types.

type

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;

On an additional note, is it possible to iterate through all members of a Record, similar to iterating through TFields or TFieldDefs?

thanks.

  • Using Delphi 11 in Firemonkey

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

娜些时光,永不杰束 2025-01-16 13:18:21

如果您有固定数量的不同类型的字段,则需要通过字符串名称访问这些字段会有点奇怪。不过,我们假设这是正确的做法。

RTTI 有点复杂(意味着您需要编写“很多”行代码)并且相当慢。当然,在你的情况下它可能足够快,所以它可能足够好。但这并不理想。

根据我的经验,人们往往过于渴望诉诸 RTTI。在大多数情况下,有更好的解决方案。

一种非 RTTI 解决方案是使用 TDictionary

另一个是这样的:

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;

where

{ 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;

If you have a fixed number of fields of different types, it is somewhat strange that you need to access these by string names. Still, let's assume this is the right thing to do.

RTTI is a bit complicated (meaning that you need to write "many" lines of code) and rather slow. Sure, it will probably be fast enough in your case, so it will probably be good enough. But it isn't ideal.

In my experience, people are often too eager to resort to RTTI. In most cases, there are better solutions.

One non-RTTI solution would be to use a TDictionary<string, Variant>.

Another would be like this:

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;

where

{ 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;

Then you can do things like this:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文