Why is IEqualityComparer
not working with strings?
type
TRec = record
s: string;
end;
var
rec1, rec2: TRec;
comparer: IEqualityComparer<TRec>;
res: boolean;
begin
rec1.s := 'a';
rec2.s := 'a';
comparer := TEqualityComparer<TRec>.default;
res := comparer.equals(rec1, rec2);
showMessage(boolToStr(res));
If the TRec
entry contains a numeric value or a string of a certain length, then IEqualityComparer
works correctly. How to make this code works?
Edit:
As Rudy Velthuis noticed in comments, in fresh Delphi versions result is true for equal constant strings because they share the same memory and have the same address (so my former supposition about better RTTI is wrong).
For complex types equality default comparer still chooses low-level comparer that compares raw bytes of both records - different adresses for similar string bodies in the second case of my example.
So reliable approach is constructing own comparer to work with complex types - see the third example below.
type
TRecS = record
s: string;
end;
var
rec1, rec2: TRecS;
comparerS: IEqualityComparer<TRecS>;
cmp: IEqualityComparer<TRecS>;
res: boolean;
begin
rec1.s := 'const';
rec2.s := 'const';
comparerS := TEqualityComparer<TRecS>.default;
res := comparerS.equals(rec1, rec2);
Memo1.Lines.Add(boolToStr(res));
rec1.s := IntToStr(88);
rec2.s := IntToStr(88);
res := comparerS.equals(rec1, rec2);
Memo1.Lines.Add(boolToStr(res));
cmp := TEqualityComparer<TRecS>.Construct(
function(const Left, Right: TRecS): Boolean
begin
Result := Left.S = Right.S
end,
nil);
res := cmp.equals(rec1, rec2);
Memo1.Lines.Add(boolToStr(res));
-1 //denotes true
0
-1