I have the following class
:
TTest = class
private
FId: Integer;
FSecField: Integer;
FThirdField: Integer;
public
constructor Create(AId, ASecField, AThirdField: Integer);
// .....
end;
Then I create a TObjectDictionary
like this:
procedure TMainForm.btnTestClick(Sender: TObject);
var
TestDict: TObjectDictionary<TTest, string>;
Instance: TTest;
begin
TestDict := TObjectDictionary<TTest, string>.Create([doOwnsKeys]);
try
TestDict.Add(TTest.Create(1, 1, 1), '');
if TestDict.ContainsKey(TTest.Create(1, 1, 1)) then
ShowMessage('Match found')
else
ShowMessage('Match not found');
Instance := TTest.Create(1, 1, 1);
TestDict.Add(Instance, 'str');
if TestDict.ContainsKey(Instance) then
ShowMessage('Match found')
else
ShowMessage('Match not found');
finally
TestDict.Free;
end;
end;
The result is: "Match not found", "Match found". What should I do in order to compare the values of fields of each key but not their addresses?
The default equality comparer for an instance reference variable compares the reference and not the object. So you get object identity rather than value identity.
So you need to supply a custom equality comparer if you wish to impose value identity.
TestDict := TObjectDictionary<TTest, string>.Create(
[doOwnsKeys],
TEqualityComparer<TTest>.Construct(EqualityComparison, Hasher)
);
where EqualityComparison
, Hasher
are comparison and hash functions. They could be implemented like this:
EqualityComparison :=
function(const Left, Right: TTest): Boolean
begin
Result := (Left.FId = Right.FId)
and (Left.FSecField = Right.FSecField)
and (Left.FThirdField = Right.FThirdField);
end;
Hasher :=
function(const Value: TTest): Integer
begin
Result := BobJenkinsHash(Value.FId, SizeOf(Value.FId), 0);
Result := BobJenkinsHash(Value.FSecField, SizeOf(Value.FSecField), Result);
Result := BobJenkinsHash(Value.FThirdField, SizeOf(Value.FThirdField), Result);
end;
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