Delphi中使用记录作为TDictionary的键

14
您可以在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。
3个回答

21
是的,您可以在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;

1
它来自于Generics.Defaults并用于比较器中的所有GetHashCode函数。您的代码很容易因各种原因而失败 - 请不要这样做。 - Stefan Glienke
这将导致启用范围检查的空字符串出现范围检查错误。最好不必调用BobJenkinsHash,因为它感觉很低级。使用匿名方法和Construct比声明类更简洁。有时候这样做会感觉更好。+1 - David Heffernan
1
@newworld:这取决于在您的应用程序中空字符串的含义。要么因为您没有所有搜索信息而取消搜索,要么假定空字符串=空字符串并将其从比较中省略。 - MichaSchumann
3
你可以使用BobJenkinsHash(PChar(Value.App)^, Length(Value.App) * SizeOf(Char), 0)代替BobJenkinsHash(Value.App[1], Length(Value.App) * SizeOf(Char), 0)。这也适用于空字符串。请注意不要改变原来的意思。 - Grzegorz Skoczylas
1
BobJenkinsHash已经过时。现在您可以使用System.Hash中的THashBobJenkins.GetHashValue。 - Toon Krijthe
显示剩余4条评论

0

不必使用记录作为键,您可以使用由序列化记录组成的字符串。您可以使用类似于https://github.com/hgourvest/superobject的工具进行序列化。

由于字符串具有内置的比较语义和哈希码,因此您无需编写比较和哈希码函数。


-1

我的最佳做法应该是连接基本类型的默认哈希码。

例如:

Value.App.GetHashCode + Value.ID.GetHashCode + Value.Nr.GetHashCode;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接