在Delphi中给数组属性中的字段赋值

5

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

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;

在这种情况下,我存储的项目都是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;

我希望能够像这样更改TTest实例的FTest值:
var
  points: TMyList<TTest>;
...
points[index].Test:= 'test';

但是这样做没有任何效果。没有错误消息,但是points [index] .Test的值没有改变。

相反,我需要这样做:

var
  points: TMyList<TTest>;
  temp: TTest;
...
temp:= points[index];
temp.Test:= 'test';
points[index]:= temp;

为什么第一个版本不能正常工作?
2个回答

11
为什么第一个版本不起作用?
考虑以下代码:
points[index].Test := 'test';

编译器将索引属性转换为函数调用,因此编译器实际上编译了以下内容:
points.get(index).Text := 'test';

现在,points.get(index) 返回一个 TTest 值的副本。由于你没有将其分配给任何变量,编译器引入了一个局部变量来保存返回值。
因此,你的代码实际上变成了这样:
var
  tmp: TTest;
...
tmp := points.get(index);
tmp.Text := 'test';

这是对tmp所做的最后一件事情,因此您对tmp.Text所做的修改会被简单地丢弃,使基础对象保持不变。


当使用值类型时,这个问题很难避免。

Delphi通用的TList<T>集合允许您直接访问基础数组,从而可以直接操作存储的值。

另一种方法是使用引用而不是值。实现这一目标的一个简单方式是使用一个类而不是记录(即引用类型而非值类型)。


3
这是因为TTest是一个record。列表的getter返回实际记录的副本,这就是你要更改的内容。如果将TTest声明为class,它应该可以工作,但那时你必须注意创建和销毁它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接