TDictionary Hashing因字符串记录而被破坏

J..*_*... 7 delphi generics hash dictionary delphi-xe2

这再现了问题:

program Project1;

{$APPTYPE CONSOLE}

uses
  Generics.Collections;
type
  TStringRec = record
    s1 : string;
    s2 : string;
  end;
  TGetHash<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>)
    public
    type
      TItem = record
        HashCode: Integer;
        Key: TKey;
        Value: TValue;
      end;
      TItemArray = array of TItem;
    public
    FItems: TItemArray;
  end;
var
  LCrossRef : TDictionary<TStringRec, integer>;
  LRec : TStringRec;
  i : integer;
begin
  LCrossRef := TDictionary<TStringRec, integer>.Create();
  LRec.s1 := 'test1';
  LRec.s2 := 'test2';
  LCrossRef.Add(LRec, 1);
  LRec.s1 := 'test1';
  LRec.s2 := 'test2';
  if LCrossRef.TryGetValue(LRec, i) then begin
    writeln('ok');
  end else begin
    LCrossRef.Add(LRec, 1);
    for i := Low(TGetHash<TStringRec, integer>
                (LCrossRef).FItems)
          to High(TGetHash<TStringRec, integer>
                (LCrossRef).FItems) do
      WriteLn(TGetHash<TStringRec, integer>(LCrossRef).FItems[i].HashCode);
    WriteLn('not ok');
  end;
  ReadLn;
end.
Run Code Online (Sandbox Code Playgroud)

字典无法检索项目并HashCode为包含相同字符串的记录生成不同的字段.

这部分在QC-#122791中注明,但使用打包记录的解决方法不适用于字符串记录(至少上述示例在TStringRec声明为时也失败packed record).

这有一个明智的解决方法吗?

我目前的策略是连接原本会进入记录并使用其他字符串的字符串TDictionary<string, TValue>,但这自然不令人满意.

Dav*_*nan 6

这是已知的限制,即设计上的限制.记录的默认比较器和缓冲区仅适用于纯值类型记录,以及没有填充的记录.

设计人员可以选择使用RTTI来比较/散列记录.但是,他们选择不这样做.这种选择的一些明显合理的原因是:

  1. 他们不希望在不情愿的情况下强制使用RTTI.
  2. 使用RTTI会对性能造成严重影响.

处理此问题的方法是在使用通用集合时提供自己的比较器和哈希.

您当前连接字符串的策略不起作用.考虑'a''aa',然后'aa''a'.要使用基于文本的方法,您需要将记录序列化为JSON.

  • 这里我的问题的答案将是有用的:http://stackoverflow.com/questions/11294686/what-is-the-canonical-way-to-write-a-hasher-function-for-tequalitycomparer-const答案值得比我的孤独更多的赞成. (3认同)