delphi - Writing a generic TList of records -
i trying write generic tlist contains records of specific type. starting david's answer on question, have written class:
type tmerecordlist<t> = class(tlist<t>) public type p = ^t; private function getitem(index: integer): p; public procedure assign(source: tmerecordlist<t>); virtual; function first: p; inline; function last: p; inline; property items[index: integer]: p read getitem; end; procedure tmerecordlist<t>.assign(source: tmerecordlist<t>); var srcitem: t; begin clear; srcitem in source add(srcitem); end; function tmerecordlist<t>.first: p; begin result := items[0]; end; function tmerecordlist<t>.getitem(index: integer): p; begin if (index < 0) or (index >= count) raise eargumentoutofrangeexception.createres(@sargumentoutofrange); result := @list[index]; end; function tmerecordlist<t>.last: p; begin result := items[count - 1]; end;
having methods return pointer record works (not perfectly) pointers records can used if records in use cases. using record properties , setters, these test cases work expected:
tmetestrecord = record private fid: word; ftext: string; fvalues: tintegers; procedure setid(const value: word); procedure settext(const value: string); procedure setvalues(const value: tintegers); public property id: word read fid write setid; property text: string read ftext write settext; property values: tintegers read fvalues write setvalues; end; // testsetitem1 rl2[0] := rl1[0]; // testsetitem2 r.id := 9; r.text := 'xxxx'; r.values := [9, 99, 999, 9999]; rl1[0] := r; // testassignempty (rl0 empty... after assign should rl2) rl2.assign(rl0); // testassigndeepcopies (modifications after assign should not affect both records) rl2.assign(rl1); r.id := 9; r.text := 'xxxx'; r.values := [9, 99, 999, 9999]; rl1[0] := r;
problem 1 - modifying contained record
... test case compiles , runs not work desired:
// testsetitemfields rl1[0].id := 9; rl1[0].text := 'xxxx'; rl1[0].values := [9, 99, 999, 9999];
modifications applied temporary copy of record , not 1 stored in list. know known , expected behaviour, documented in other questions.
but... there way around it? thinking maybe if tmerecordlist<>.items property had setter compiler maybe desired. it? know david has got solution, hinted @ in question... can't seem find on own.
this nice have, allow me have way of using list identical (or almost) of tlist of objects. having same interface means change objects records , viceversa, when need arises.
problem 2 - interface ambiguity
having tlist<> return record pointer pose interface ambiguity problems. tlist<> methods accept t parameters, , know being records, these going passed value. should these methods do? should rethink them? i'm talking these sets of methods:
- remove , removeitem
- extract , extractitem
- contains indexof, indexofitem , lastindexof
there ambiguity how these should test contained items see if match parameter record value. list contain identical records , become source of bugs in user code.
i tried not deriving tlist<>, not have these methods, mess. couldn't write class similar tlist without writing own tlisthelper. unfortunately system.generics.collections's 1 has needed fields private, fcount, , cannot used outside unit.
problem 1
your items property not marked being default. hence erroneous code picking base class default property. add default
keyword items property:
property items[index: integer]: p read getitem; default;
problem 2
this consequence of deriving tlist<t>
. not recommend doing that. encapsulate instance of tlist<t>
, therefore define interface explicitly rather inheriting it. or implement list functionality directly in code. after all, it's not more wrapper around dynamic array.
for worth classes don't use tlist<t>
@ decision happy when emba broke class in recent release.
Comments
Post a Comment