如何在 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;
我正在尝试使用以下代码创建不区分大小写的 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;