I found that Delphi generics TObjectList with an attached TComparer behaves very strange.

I found that Delphi generics TObjectList with an attached TComparer behaves very strange. I struggle into that problem while switching my code from normal TObjectList to TObjectList.

The heavy to understand background is the fact that the Remove(const Value: T) suddenly uses "undocumented" the TComparer and not the pointer. That works fine as long as there are not "key doubles" in the list. I know this sounds rather technical and I have prepared a small sample to make the problem visible.

RunTest(False) works RunTest(True) fails

Perhaps I should stop using TObjectList.Create(const AComparer: IComparer; AOwnsObjects: Boolean)


---
unit uTest;
interface
uses classes;

type

TPerson = class(TObject)
public
Name: string;
RecID: integer;
constructor Create(AName: string; ARecID: integer);
end;

TMyTest = class(TObject)
procedure RunTest(AAddComparer: boolean);
end;

implementation

uses system.Generics.Collections, system.Generics.Defaults, sysUtils;

procedure TMyTest.RunTest(AAddComparer: boolean);
var
oList: TObjectList;
oPers: TPerson;
iRemovedIdx, iLast: integer;
comparison: TComparison;
begin

if AAddComparer then
begin
comparison:=
function(const left, right: TPerson): Integer
begin
Result:= CompareText(left.Name,right.Name);
end;
oList:= TObjectList.Create(TComparer.Construct(comparison),True);
end
else begin
oList:= TObjectList.Create;
end;

try
oList.Add(TPerson.Create('Tom',1));
oList.Add(TPerson.Create('Tom',2));
iLast:= oList.Count-1;
oPers:= oList[iLast];
Assert(oPers.RecID = 2); // was the last record select?
iRemovedIdx:= oList.Remove(oPers);
Assert(iRemovedIdx=iLast) // was the last record deleted?
finally
oList.Free;
end;
end;

constructor TPerson.Create(AName: string; ARecID: integer);
begin
inherited Create;
Name:= AName;
RecID:= ARecID;
end;
end.

Comments