Reputation: 1646
I'm trying the following code to create a case insensitive 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;
However the IndexOf call always returns -1. Should this work? Any suggestions appreciated.
Update: It looks like the comparer is used for sorting, but not for IndexOf. A separate "EqualityComparer" is used for IndexOf, so the question becomes how to change it?
Update2: I just wanted to add to Johan's answer that the list can then be created like so:
MyCIList := TCaseInsensitiveList<string>.Create(
TStringComparer.OrdinalIgnoreCase(),
TStringComparer.OrdinalIgnoreCase());
Upvotes: 3
Views: 897
Reputation: 1646
This issue has been resolved in Spring4D hotfix 1.2.1. With the change the code below works as expected.
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;
Upvotes: 2
Reputation: 76693
The code of IndexOf looks like this:
function TList<T>.IndexOf(const item: T; index, count: Integer): Integer;
begin
Result := TArray.IndexOf<T>(fItems, item, index, count, EqualityComparer);
end;
The EqualityComparer is a property that calls GetEqualityComparer which looks like:
protected
class function GetEqualityComparer: IEqualityComparer<T>; static;
This static
means the method cannot be overriden in a child class.
You need to edit the source of Spring and make the following change:
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.
.......
^^^^^^^^
Now you can create your own TCaseInsensitiveList
like so:
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;
Or alternatively you can declare the base GetEqualityComparer
class function to be virtual and override that in a child class.
There is a cost to making the GetEqualityComparer
virtual, which is why I choose to make the underlying class variable protected.
Upvotes: 1