I have a class which stores generic items in an array. These items are accessed by a default array property:
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;
In this case the items I am storing are all of the type TTest which also has its own properties:
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;
I want to be able to change the value of FTest for an instance of TTest like this:
var
points: TMyList<TTest>;
...
points[index].Test:= 'test';
but this doesn't do anything. There is no error message but the value of points[index].Test doesn't change.
Instead I have to do this:
var
points: TMyList<TTest>;
temp: TTest;
...
temp:= points[index];
temp.Test:= 'test';
points[index]:= temp;
Why does the first version not work?
Why does the first version not work?
Consider this code
points[index].Test := 'test';
The indexed property is converted by the compiler into the a function call and so the compiler effectively compiles this:
points.get(index).Text := 'test';
Now, points.get(index)
returns a copy of the TTest
value. Since you don't assign that to anything, the compiler introduces a local variable to hold the return value.
So your code becomes, in effect:
var
tmp: TTest;
...
tmp := points.get(index);
tmp.Text := 'test';
That's the last thing that is ever done with tmp
, and so the modifications that you make to tmp.Text
are simply discarded leaving the underlying object untouched.
This issue is pretty hard to get around when working with value types.
The generic Delphi TList<T>
collection allows you direct access to the underlying array, which allows you to operate on the stored values directly.
Another approach is to use a reference rather than a value. One simple way to achieve that is to use a T
that is a class rather than a record, i.e. a reference type rather than a value type.
It is because TTest
is a record
. The getter of the list returns a copy of the actual record and that is what you are changing. It should work when you declare TTest
as a class
, but then you have to take care of creating and destroying it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With