在Delphi中如何拥有一个实现IComparable并继承自TEqualityComparer的类?

时间:2015-08-19 04:46:26

标签: delphi dictionary

要解释我的问题,我会在Embarcadero的网站上使用与TDictionary example非常相似的内容,但我的课程会实现IComparable

在Delphi(XE7)中:

TCity = class(TInterfacedObject, IComparable)
  Country: String;
  Latitude: Double;
  Longitude: Double;

  function CompareTo(Obj: TObject): Integer;
end;

我希望TDictionary以城市作为键:

Dictionary := TDictionary<TCity, string>.Create;

CityA := TCity.Create;
CityA.Country := 'United Kingdom';
CityA.Latitude := 51.5;
CityA.Longitude := -0.17;
Dictionary.Add(CityA, 'London');

现在,如果我使用与CityA.CompareTo(CityB)返回0之前相同的值创建新城市,例如:

CityB := TCity.Create;
CityB.Country := 'United Kingdom';
CityB.Latitude := 51.5;
CityB.Longitude := -0.17;

在将CityB添加到词典之前,我期待:

Dictionary.ContainsKey(CityB)

将使用我的CompareTo实施,ContainsKey将返回True,但事实并非如此。我的班级似乎还需要继承TEqualityComparer

那么如何将ContainsKey使用的相等比较器添加到我的班级,而CompareTo已经存在?

我知道我可以使用TDelegatedEqualityComparer和匿名方法来创建在创建字典时使用的自定义比较器。类似的东西:

Dictionary := TDictionary<TCity, string>.Create(CityComparer)

但有没有办法在TCity中包含相等比较器,这样在创建字典时我不需要一个?

2 个答案:

答案 0 :(得分:7)

你在这里混合两件事。 IComparable用于排序。

IEqualityComparer<T>用于检查两个项是否相等,但它还具有字典在内部使用的GetHashCode方法。

对于对象,IEqualityComparer<T>的默认实现使用TObject中的虚拟GetHashCodeEquals方法。因此,如果您想将两个不同的实例视为相等,则有两个选项:

  1. 在您的班级

  2. 中覆盖这两种方法
  3. 提供IEqualityComparer<T>

  4. 的自定义实现

答案 1 :(得分:1)

据我所知。如果你没有提供IEqualityComparer,那么构造函数TDictionary将使用默认的密钥。

查看构造函数:

constructor TDictionary<TKey,TValue>.Create(ACapacity: Integer; const AComparer: IEqualityComparer<TKey>);
var
  cap: Integer;
begin
  inherited Create;
  if ACapacity < 0 then
    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
  FComparer := AComparer;
  if FComparer = nil then
    FComparer := TEqualityComparer<TKey>.Default; // <-- HERE!
  SetCapacity(ACapacity);
end;

她在GetBucketIndex使用

    function TDictionary<TKey,TValue>.GetBucketIndex(const Key: TKey; HashCode: Integer): Integer;
begin    
 ...
        // Found: return location.
        if (hc = HashCode) and FComparer.Equals(FItems[Result].Key, Key) then
...
end;

所以不,你必须在构造函数中提供IComparable

相关问题