在delphi中分配给数组属性中的字段

cha*_*ieb 5 delphi

我有一个将通用项目存储在数组中的类。这些项目由默认数组属性访问:

TMyList<TData> = class
private
  items: array of TItem<TData>;
public
  function get(position: integer): TData;
  procedure edit(position: integer; data: TData);
  property Values[position: integer]: TData read get write edit; default;
end;

implementation
function TMyList<TData>.get(position: integer): TData;
begin
result:= items[position];
end;

procedure TMyList<TData>.edit(position: integer; data: TData);
var
  item: TItem<TData>;
begin
  items[position]:= item;
end;
end;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我存储的项目都是 TTest 类型,它也有自己的属性:

TTest = record
  private
      FTest: string;
      procedure setFTest(const Value: string);
  public
    property Test: string read FTest write setFTest;
end;

implementation
procedure TColouredPoint.setFTest(const Value: String);
begin
  FTest:= Value;
end;
end;
Run Code Online (Sandbox Code Playgroud)

我希望能够像这样更改 TTest 实例的 FTest 值:

var
  points: TMyList<TTest>;
...
points[index].Test:= 'test';
Run Code Online (Sandbox Code Playgroud)

但这没有任何作用。没有错误消息,但 points[index].Test 的值没有改变。

相反,我必须这样做:

var
  points: TMyList<TTest>;
  temp: TTest;
...
temp:= points[index];
temp.Test:= 'test';
points[index]:= temp;
Run Code Online (Sandbox Code Playgroud)

为什么第一个版本不起作用?

Dav*_*nan 11

为什么第一个版本不起作用?

考虑这个代码

points[index].Test := 'test';
Run Code Online (Sandbox Code Playgroud)

索引属性由编译器转换为函数调用,因此编译器有效地编译:

points.get(index).Text := 'test';
Run Code Online (Sandbox Code Playgroud)

现在,points.get(index)返回TTest值的副本。由于您没有将其分配给任何东西,因此编译器引入了一个局部变量来保存返回值。

所以你的代码实际上变成了:

var
  tmp: TTest;
...
tmp := points.get(index);
tmp.Text := 'test';
Run Code Online (Sandbox Code Playgroud)

这是使用 完成的最后一件事,tmp因此您所做的修改会tmp.Text被简单地丢弃,而不会触及底层对象。


在使用值类型时,这个问题很难解决。

通用 DelphiTList<T>集合允许您直接访问底层数组,这允许您直接对存储的值进行操作。

另一种方法是使用引用而不是值。实现这一点的一种简单方法是使用T类而不是记录,即引用类型而不是值类型。