Delphi,记录类型属性,记录字段赋值:需要赋值到记录的本地副本 [英] Delphi, record type property, record field assignment: Assignment to local copy of record expected

查看:15
本文介绍了Delphi,记录类型属性,记录字段赋值:需要赋值到记录的本地副本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在问题"Left side cannot be assigned to" for record type properties in Delphi上,有来自Toon Krijthe的an answer演示了如何通过在记录的声明中使用属性来完成对记录属性的字段的赋值。为便于参考,以下是由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;

我很清楚为什么vclDeveloper的原始代码在记录中没有setter的情况下会出现"无法将左侧赋值给"的错误。如果像上面的代码一样为属性TRec.A定义了setter,为什么赋值Rec.A := 21;不会引发错误,这对我来说也很清楚。

我不明白的是,为什么赋值Rec.A := 21;会将值21赋给TForm1的字段FRec.FA。我原本希望将该值分配给FRec本地临时副本的FA字段,而不是FRec.FA本身。有谁能解释一下这里发生了什么事吗?

推荐答案

这是一个很棒的问题!

您看到的行为是属性实现细节的结果。对于直接字段属性获取方法和函数属性获取方法,编译器实现属性的方式不同。

当您写作时

Rec.A := 21;

编译器看到Rec并知道它是一个属性。由于getter是一个直接的字段getter,编译器只需将Rec替换为FRec,并编译代码,就像您编写的

一样
FRec.A := 21;

然后编译器遇到A属性并使用setter方法,因此您的赋值变成

FRec.SetA(21);

因此您观察到了这些行为。

假设您有一个函数getter,而不是直接的字段getter

property Rec: TRec read GetRec;
....
function TForm1.GetRec: TRec;
begin
  Result := FRec;
end;

在该方案中,

Rec.A := 21;

更改。取而代之的是,编译器声明了一个隐式局部变量,代码编译如下:

var
  __local_rec: TRec;
....
__local_rec := GetRec;
__local_rec.A := 21;

对我来说,显而易见的是,这样的程序的行为不应该取决于属性获取程序是直接的字段获取程序还是函数获取程序。这似乎是属性功能和增强的记录功能之间交互的设计缺陷。


以下是一个非常简洁地演示该问题的完整程序:

{$APPTYPE CONSOLE}

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

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

type
  TMyClass = class
  private
    FRec: TRec;
    function GetRec: TRec;
  public
    property RecDirect: TRec read FRec;
    property RecFunction: TRec read GetRec;
  end;

var
  Obj: TMyClass;

function TMyClass.GetRec: TRec;
begin
  Result := FRec;
end;

begin
  Obj := TMyClass.Create;
  Obj.RecDirect.A := 21;
  Writeln(Obj.FRec.FA);

  Obj := TMyClass.Create;
  Obj.RecFunction.A := 21;
  Writeln(Obj.FRec.FA);
end.

输出

21
0

这篇关于Delphi,记录类型属性,记录字段赋值:需要赋值到记录的本地副本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆