如何在Spring4d

时间:2017-05-17 21:08:13

标签: delphi delphi-10.1-berlin 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调用始终返回-1。这有用吗?任何建议表示赞赏。

更新:看起来比较器用于排序,但不适用于IndexOf。一个单独的“EqualityComparer”用于IndexOf,所以问题变成了如何改变它?

Update2:我只想添加Johan的答案,然后可以像这样创建列表:

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

2 个答案:

答案 0 :(得分:1)

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表示无法在子类中覆盖该方法。

您需要编辑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类函数声明为虚拟,并在子类中重写它。

使GetEqualityComparer虚拟成本是有代价的,这就是我选择保护基础类变量的原因。

答案 1 :(得分:1)

此问题已在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;