Delphi Использование записей в качестве ключа в TDictionary

Можно ли использовать запись в качестве ключевого значения в TDictionary? Я хочу найти объекты на основе комбинации строк, integer и integer.

TUserParKey=record
  App:string;
  ID:integer;
  Nr:integer;
end;

...

var
  tmpKey:TUserParKey;
  tmpObject:TObject;
begin
  tmpObject:= TTObject.Create(1); 
  tmpKey.App:='1';
  tmpKey.ID :=1;
  tmpKey.Nr :=1;

  DTUserPars.Add(tmpKey,tmpObject)

...

var
  tmpKey:TUserParKey;
begin
  tmpKey.App:='1';
  tmpKey.ID :=1;
  tmpKey.Nr :=1;

  if not DTUserPars.TryGetValue(tmpKey,Result) then begin
    result := TTObject.Create(2); 
  end;

Возвращает объект 2.

Ответы

Ответ 1

Да, вы можете использовать записи как ключи в TDictionary, но при создании словаря вы должны предоставить свой собственный IEqualityComparer, потому что по умолчанию для записей просто нечетное двоичное сравнение записи. Это не удается для записи, содержащей строку, поскольку она просто сравнивает указатель на эту строку, которая может быть другой, даже если строка содержит одно и то же значение.

Такой сравнитель будет выглядеть так:

type
  TUserParKeyComparer = class(TEqualityComparer<TUserParKey>)
    function Equals(const Left, Right: TUserParKey): Boolean; override;
    function GetHashCode(const Value: TUserParKey): Integer; override;
  end;

function TUserParKeyComparer.Equals(const Left, Right: TUserParKey): Boolean;
begin
  Result := (Left.App = Right.App) and (Left.ID = Right.ID) and (Left.Nr = Right.Nr);
end;

function TUserParKeyComparer.GetHashCode(const Value: TUserParKey): Integer;
begin
  Result := BobJenkinsHash(PChar(Value.App)^, Length(Value.App) * SizeOf(Char), 0);
  Result := BobJenkinsHash(Value.ID, SizeOf(Integer), Result);
  Result := BobJenkinsHash(Value.Nr, SizeOf(Integer), Result);
end;