IEqualityComparer и строка - PullRequest
       23

IEqualityComparer и строка

0 голосов
/ 12 октября 2018

Почему IEqualityComparer не работает со строками?

type
    TRec = record
        s: string;
    end;

var
    rec1, rec2: TRec;
    comparer: IEqualityComparer<TRec>;
    res: boolean;
begin
    rec1.s := 'a';
    rec2.s := 'a';

    comparer := TEqualityComparer<TRec>.default;
    res := comparer.equals(rec1, rec2);
    showMessage(boolToStr(res));

Если запись TRec содержит числовое значение или строку определенной длины, то IEqualityComparer работает правильно.Как сделать так, чтобы этот код работал?

1 Ответ

0 голосов
/ 12 октября 2018

Редактировать:

Как заметил Руди Велтуис в комментариях, в свежих версиях Delphi результат верен для равных константных строк, поскольку они совместно используют одну и ту же память и имеюттот же адрес (поэтому мое прежнее предположение о лучшем RTTI неверно).

Для сложных типов равенство по умолчанию для сравнения по-прежнему выбирается низкоуровневый компаратор, который сравнивает необработанные байты обеих записей - разные адреса для похожих строковых тел во втором случаемоего примера.

Таким надежным подходом является создание собственного компаратора для работы со сложными типами - см. третий пример ниже.

type
    TRecS = record
        s: string;
    end;
 var
    rec1, rec2: TRecS;
    comparerS: IEqualityComparer<TRecS>;
    cmp: IEqualityComparer<TRecS>;
    res: boolean;
begin
    rec1.s := 'const';
    rec2.s := 'const';
    comparerS := TEqualityComparer<TRecS>.default;
    res := comparerS.equals(rec1, rec2);
    Memo1.Lines.Add(boolToStr(res));

    rec1.s := IntToStr(88);
    rec2.s := IntToStr(88);
    res := comparerS.equals(rec1, rec2);
    Memo1.Lines.Add(boolToStr(res));

    cmp := TEqualityComparer<TRecS>.Construct(
                      function(const Left, Right: TRecS): Boolean
                      begin
                          Result := Left.S = Right.S
                      end,
                      nil);
   res := cmp.equals(rec1, rec2);
   Memo1.Lines.Add(boolToStr(res));

    -1  //denotes true
    0  
    -1
...