如何在 Spring4d 中创建和使用不区分大小写的 IList<string>

How to create and use a case insensitive IList<string> in Spring4d

我正在尝试使用以下代码创建不区分大小写的 IList:

procedure TForm1.ListButtonClick(Sender: TObject);
var
  MyList: IList<string>;
begin
  MyList := TCollections.CreateList<string>(TStringComparer.OrdinalIgnoreCase());
  MyList.AddRange(['AAA', 'BBB', 'CCC']);
  Memo1.Lines.Add(MyList.IndexOf('aaa').ToString);
end;

但是 IndexOf 调用总是 returns -1。这应该工作吗?任何建议表示赞赏。

更新:看起来比较器用于排序,而不是用于IndexOf。 IndexOf使用了单独的"EqualityComparer",那么问题就变成了怎么改?

更新 2:我只是想补充 Johan 的回答,然后可以像这样创建列表:

MyCIList := TCaseInsensitiveList<string>.Create(
  TStringComparer.OrdinalIgnoreCase(),
  TStringComparer.OrdinalIgnoreCase());

IndexOf 的代码如下所示:

function TList<T>.IndexOf(const item: T; index, count: Integer): Integer;
begin
  Result := TArray.IndexOf<T>(fItems, item, index, count, EqualityComparer);
end;

EqualityComparer 是一个 属性,它调用 GetEqualityComparer,它看起来像:

protected
  class function GetEqualityComparer: IEqualityComparer<T>; static;

static 表示该方法不能在子 class 中覆盖。

您需要编辑 Spring 的源代码并进行以下更改:

Spring.Collections.Base

103:   TEnumerableBase<T> = class abstract(TEnumerableBase, IEnumerable<T>)
106:   protected
108:   class var fEqualityComparer: IEqualityComparer<T>;  
//     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//Move this line from private to the protected section.
.......

                                                                ^^^^^^^^

现在您可以像这样创建自己的 TCaseInsensitiveList

type
  TCaseInsensitiveList<T> = class(Spring.Collections.TList<T>)
    constructor Create(const Comparer: IComparer<T>; 
                       const EqualityComparer: IEqualityComparer<T>);
  end;
  .....
constructor TCaseInsensitiveList<T>.Create(
             const Comparer: IComparer<T>; 
             const EqualityComparer: IEqualityComparer<T>);
begin
  inherited Create(Comparer);
  Self.fEqualityComparer:= EqualityComparer;
end;

或者您可以将基础 GetEqualityComparer class 函数声明为虚拟函数并在子 class.

中覆盖它

使 GetEqualityComparer 虚拟化是有代价的,这就是为什么我选择使基础 class 变量受保护。

此问题已在 Spring4D 修补程序 1.2.1 中得到解决。通过更改,下面的代码按预期工作。

procedure TForm1.ListButtonClick(Sender: TObject);
var
  MyList: IList<string>;
begin
  MyList := TCollections.CreateList<string>(TStringComparer.OrdinalIgnoreCase());
  MyList.AddRange(['AAA', 'BBB', 'CCC']);
  Memo1.Lines.Add(MyList.IndexOf('aaa').ToString);  // Correctly returns 0.
end;