我有一个将通用项目存储在数组中的类。这些项目由默认数组属性访问:
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
类而不是记录,即引用类型而不是值类型。