当前位置:  开发笔记 > 编程语言 > 正文

"左侧不能分配给"Delphi中的记录类型属性

如何解决《"左侧不能分配给"Delphi中的记录类型属性》经验,为你挑选了4个好方法。

我很想知道为什么Delphi将记录类型属性视为只读:

  TRec = record
    A : integer;
    B : string;
  end;

  TForm1 = class(TForm)
  private
    FRec : TRec;
  public
    procedure DoSomething(ARec: TRec);
    property Rec : TRec read FRec write FRec;
  end;

如果我尝试为Rec属性的任何成员赋值,我将得到"左侧无法分配"错误:

procedure TForm1.DoSomething(ARec: TRec);
begin
  Rec.A := ARec.A;
end;

允许对底层字段执行相同操作:

procedure TForm1.DoSomething(ARec: TRec);
begin
  FRec.A := ARec.A;
end;

这种行为有什么解释吗?



1> Allen Bauer..:

由于"Rec"是一个属性,编译器对它的处理方式略有不同,因为它必须首先评估属性decl的"读取".考虑一下,这在语义上等同于您的示例:

...
property Rec: TRec read GetRec write FRec;
...

如果你这样看,你可以看到第一个引用"Rec"(在点'.'之前),必须调用GetRec,它将创建Rec的临时本地副本.这些临时设计在设计上是"只读的".这就是你遇到的.

你可以在这里做的另一件事是将记录的各个字段作为包含类的属性分解:

...
property RecField: Integer read FRec.A write FRec.A;
...

这将允许您通过属性直接分配给类实例中该嵌入记录的字段.



2> Toon Krijthe..:

是的,这是一个问题.但是使用记录属性可以解决问题:

type
  TRec = record
  private
    FA : integer;
    FB : string;
    procedure SetA(const Value: Integer);
    procedure SetB(const Value: string);
  public
    property A: Integer read FA write SetA;
    property B: string read FB write SetB;
  end;

procedure TRec.SetA(const Value: Integer);
begin
  FA := Value;
end;

procedure TRec.SetB(const Value: string);
begin
  FB := Value;
end;

TForm1 = class(TForm)
  Button1: TButton;
  procedure Button1Click(Sender: TObject);
private
  FRec : TRec;
public
  property Rec : TRec read FRec write FRec;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Rec.A := 21;
  Rec.B := 'Hi';
end;

这编译和工作没有问题.


+1注意你的解决方案并不坏,但是它的用户需要记住,如果他们将属性更改为"属性Rec:TRec read GetRec write FRec;",则分配技巧将失败(因为GetRec将返回*副本)*因为记录是*值类型*).

3> vehystrix..:

我经常使用的解决方案是将属性声明为指向记录的指针.

type
  PRec = ^TRec;
  TRec = record
    A : integer;
    B : string;
  end;

  TForm1 = class(TForm)
  private
    FRec : TRec;

    function GetRec: PRec;
    procedure SetRec(Value: PRec);
  public
    property Rec : PRec read GetRec write SetRec; 
  end;

implementation

function TForm1.GetRec: PRec;
begin
  Result := @FRec;
end;  

procedure TForm1.SetRec(Value: PRec);
begin
  FRec := Value^;
end;

这样,直接分配Form1.Rec.A := MyInteger将起作用,但也Form1.Rec := MyRec可以按预期将所有值复制MyRecFRec字段中.

这里唯一的缺陷是,当你想要实际检索要使用的记录副本时,你将不得不这样做 MyRec := Form1.Rec^



4> Barry Kelly..:

编译器阻止您分配临时.允许使用C#中的等价物,但它没有效果; Rec属性的返回值是基础字段的副本,并且分配给副本上的字段是一个nop.

推荐阅读
勤奋的瞌睡猪_715
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有