【问题标题】:read write property of type record记录类型的读写属性
【发布时间】:2022-02-03 21:08:42
【问题描述】:

声明记录类型的属性有什么缺点吗?

  TMyObject = class(TObject)
  private
    FSomeRecord: TMyRecord;
  public
    property SomeRecord: TMyRecord read FSomeRecord write FSomeRecord;
  end;

指令Myobject.SomeRecord.xxx := yyy 将如何在幕后工作(我认为这实际上行不通)?

如果它不能工作,如何处理记录属性?避免它并像下面这样声明 TMyobject 会更好吗?

  TMyObject = class(TObject)
  public
    SomeRecord: TMyRecord;
  end;

【问题讨论】:

  • 只有当您需要能够一次读取或写入整个记录的值而不是访问记录的各个字段时,使用记录类型属性才有用。例如,当您尝试使用一个命令将单独记录的值分配给对象记录时,反之亦然。例如,对于在不同对象之间复制记录可能很有用。

标签: delphi


【解决方案1】:

你说得对,Myobject.SomeRecord.xxx := yyy 不会按照你想要的方式工作。它将调用属性 getter,返回记录的副本,然后您将更新副本的 xxx 字段,而不是原始字段。本质上,生成的代码会是这样的:

var tmp: TMyRecord;
tmp = Myobject.FSomeRecord;
tmp.xxx := yyy;

除非属性需要 RTTI,否则没有充分的理由声明一个简单直接访问字段的读+写属性。只需公开对该字段的公共访问权限即可。

【讨论】:

  • 谢谢remy :) 我刚刚更新了一点问题,也以这种方式询问如何处理记录?最好在财产中避免它们?
  • 我已经更新了答案
  • 我不确定旧的 Delphi 版本,但在 Delphi 10.3 中调用 Myobject.SomeRecord.xxx := yyy 将返回 E2064 Left side cannot be assigned to 编译器错误,因为编译器希望您提供另一个匹配的记录类型来读取或写入值.
  • @SilverWarior 这是因为现代版本足够聪明,可以知道代码正在写入一个没有效果的临时文件。旧版本没有警告。
  • 定义“旧”:-)。我记得几年前看到过这个(XE5 左右)。我相信这是一个返回记录的函数,但可能记错了......
【解决方案2】:

避免这种情况的一种方法是将属性声明为记录的指针(如果您只需要访问记录中的字段/方法):

TYPE
  TMyRecord = RECORD
                Field1  : INTEGER;
              END;
  PMyRecord = ^TMyRecord;

TYPE
  TMyClass  = CLASS
          PRIVATE
            FMyRecord   : TMyRecord;
            FUNCTION    GetRec : PMyRecord;
          PUBLIC
            PROPERTY    MyRec : PMyRecord Read GetRec;
          END;

{ TMyClass }

FUNCTION TMyClass.GetRec : PMyRecord;
  BEGIN
    Result:=@FMyRecord
  END;

.
.
.
VAR
  MC    : TMyClass;
.
.
.
MC.MyRec.Field1:=12
.
.
.

由于“扩展语法”,您可以将正常语法短路

MC.MyRec^.Field1:=12

MC.MyRec.Field1:=12

但不是以下用途:

VAR NewRec : TMyRecord := MC.MyRec;

必须编码为

VAR NewRec : TMyRecord := MC.MyRec^;

除非您为 PMyRecord 引入 RECORD HELPER,以实现对 TMyRecord 的隐式转换:

TYPE
  PMyRecHelper  = RECORD HELPER FOR PMyRecord
                    CLASS OPERATOR Implicit(P : PMyRecord) : TMyRecord;
                  END;

{ PMyRecHelper }

CLASS OPERATOR PMyRecHelper.Implicit(P : PMyRecord) : TMyRecord;
  BEGIN
    Result:=P^
  END;

不幸的是,上面的代码在编译时不起作用。 Delphi 不允许在记录助手中使用运算符重载...

所以在实现最后一项之前,您只有一个半工作实现...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多