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

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

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;

Вместо использования записи в качестве ключа вы можете использовать строку, состоящую из сериализованной записи. Вы можете использовать что-то вроде https://github.com/hgourvest/superobject для сериализации.

Поскольку строки имеют встроенную семантику сравнения и хэш-коды, вам не нужно писать функции сравнения и хэш-коды.

Мой лучший подход - объединить хэш-код по умолчанию для базовых типов.

Например:

Value.App.GetHashCode + Value.ID.GetHashCode + Value.Nr.GetHashCode;
Другие вопросы по тегам