5

我的问题很简单。我有一个具有以下代码的 dwsUnit:

type
  TPointCoord = record
    X: Float;
    Y: Float;
    Z: Float;
  end;

type
  TMyClass = class
  private
    fPosition: TPointCoord;

    function GetPosition: TPointCoord;
    procedure SetPosition(Val: TPointCoord);
  public
    property Position: TPointCoord read GetPosition write SetPosition;
    constructor Create;
end;

function TMyClass.GetPosition: TPointCoord;
begin
  Result := fPosition;
end;

procedure TMyClass.SetPosition(Val: TPointCoord);
begin
  fPosition := Val;
end;

constructor TMyClass.Create;
begin
  inherited Create;
  fPosition.X := 1;
  fPosition.Y := 2;  
  fPosition.Z := 3;    
end;

var
  mc: TMyClass;
begin
  mc := TMyClass.Create;
  mc.Position.X := 2;   //Syntax Error
end.

在 mc.Position.X(或 Position.Y 或 Z)我得到:

Syntax Error: Cannot assign a value to the left-side argument [line: 42, column: 17]

这是什么意思?如果是属性,记录是只读的吗?以及我如何从 Delphi Side 访问它。(第二个问题,没什么大不了的)

4

3 回答 3

2

此错误的原因是因为您使用的是记录类型的属性。

记录类型是一种值类型,这意味着它是在赋值时复制而不是被引用(如类),因此返回记录的函数(或属性)将复制并返回不同的记录。

所以你的线

mc.Position.X := 2

等效于

temp := mc.getPosition;
temp.X := 2;

“temp”是与 fPosition 不同的变量/存储,因此代码不会更改 fPosition.X,它只会更改“隐藏”临时副本的 X 字段。

由于这通常不太可能是您所追求的,因此 DWS 编译器,就像 Delphi 一样,会引发错误。

典型的解决方案是提供一个独特的 PositionX 属性,它将提供对 fPosition 的 X 字段的访问,例如

property PositionX : TPointCoord read (FPosition.X) write (FPosition.X);

或者,如果您需要的不仅仅是分配的 X 字段,您可以使用显式的 getter/setter。

另一种解决方案是使用引用类型(类 fi),尽管这对于位置或坐标可能不是很实用。

于 2014-08-12T10:04:35.257 回答
2

虽然 LHirstov 代码可以与 DWScript 一起使用,但相同的特定代码可能不适用于某些旧版本的 Delphi。

因此,对于那些使用旧版本 Delphi 的人,我建议只需向 TmyClass 添加更多属性,而不是修改记录。

您需要的只是添加三个新属性(每个位置参数一个),然后定义它们的 Getter/Setter 方法来单独修改这些特定参数。

type
  TPointCoord = record
    X: Float;
    Y: Float;
    Z: Float;
  end;

  TMyClass = class
  private
    fPosition: TPointCoord;

    function GetPosition: TPointCoord;
    function GetPositionX: Float;
    function GetPositionY: Float;
    function GetPositionZ: Float;
    procedure SetPosition(Val: TPointCoord);
    procedure SetPositionX(Val: Float);
    procedure SetPositionY(Val: Float);
    procedure SetPositionZ(Val: Float);
  public
    property Position: TPointCoord read GetPosition write SetPosition;
    property PositionX: TPointCoord read GetPositionX write SetPositionX;
    property PositionY: TPointCoord read GetPositionY write SetPositionY;
    property PositionZ: TPointCoord read GetPositionZ write SetPositionZ;
    constructor Create;
end;

function TMyClass.GetPosition: TPointCoord;
begin
  Result := fPosition;
end;

procedure TMyClass.SetPosition(Val: TPointCoord);
begin
  fPosition := Val;
end;

function TMyClass.GetPositionX: Float;
begin
  Result := fPosition.X;
end;

procedure TMyClass.SetPositionX(Val: Float);
begin
  fPosition.X := Val;
end;


function TMyClass.GetPositionX: Float;
begin
  Result := fPosition.Y;
end;

procedure TMyClass.SetPositionY(Val: Float);
begin
  fPosition.Y := Val;
end;

function TMyClass.GetPositionX: Float;
begin
  Result := fPosition.Z;
end;

procedure TMyClass.SetPositionZ(Val: Float);
begin
  fPosition.Z := Val;
end;

因此,最后您可以使用以下方式访问特定的位置参数:

mc.PositionX := 2;

现在您可能会问自己,我还需要旧的 Position 属性吗?虽然您在技术上不需要它,但当您需要读取或写入整个位置记录时,它仍然可以派上用场。

于 2014-08-12T06:53:36.937 回答
1

您拥有 TPointCoord 类型的属性,并且您只想分配 X 坐标,这就是您遇到错误的原因。如果要分别处理 X、Y 和 Z,则必须为它们中的每一个分配属性。这是 X 的一个示例:

type
  TPointCoord = record
  private
    fX: real;
    fY: real;
    fZ: real;
    function GetX: real;
    procedure SetX(value: real);
  public
    property X: real read GetX write SetX;
  end;

function TPointCoord.GetX: real;
begin
  Result:=fX;
end;

procedure TPointCoord.SetX(value: Real);
begin
  fX:=Value;
end;

有了上面的例子,你的陈述mc.Position.X := 2;就可以了。

于 2014-08-12T05:18:02.573 回答