【问题标题】:delphi Using records as key in TDictionarydelphi 使用记录作为 TDictionary 中的键
【发布时间】:2020-11-09 09:15:38
【问题描述】:

可以在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。

【问题讨论】:

    标签: delphi generics collections tdictionary


    【解决方案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;
    

    【讨论】:

    • 感谢代码。什么是 Bobjenkinshash?为什么需要它?我的哈希看起来像这样。 tmpStr:=''; for I := 1 to Value.App.length do tmpStr:=tmpStr + inttostr(ord(Value.app[i])); tmpStr:= tmpStr+inttostr(Value.ID)+inttostr(Value.Nr);结果:= StrToIntDef(tmpStr,-1);
    • 它来自 Generics.Defaults,用于比较器中的所有 GetHashCode 函数。你的代码很容易因为各种原因而失败——请不要那样做。
    • @newworld:这取决于您的应用程序中空刺的含义。要么取消搜索,因为您没有所有搜索信息,要么假设空字符串=空字符串并从比较中忽略它。
    • 您可以使用BobJenkinsHash(PChar(Value.App)^, Length(Value.App) * SizeOf(Char), 0) 代替BobJenkinsHash(Value.App[1], Length(Value.App) * SizeOf(Char), 0)。它也适用于空字符串。
    • BobJenkinsHash 已弃用。您现在可以使用 System.Hash 中的 THashBobJenkins.GetHashValue。
    【解决方案2】:

    您可以使用由序列化记录组成的字符串,而不是使用记录作为键。你可以使用https://github.com/hgourvest/superobject 之类的东西来进行序列化。

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

    【讨论】:

      【解决方案3】:

      我最好的方法应该是联合基本类型的默认哈希码。

      例如:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-07
        • 2011-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多