好的,正如我们在 cmets 中发现的,我们有 2 个任务:
- 如何查找
TObjectList 是否已经包含一个项目(所以新项目是重复的)
- 如何管理
TImageList 中的文件图标以减少内存使用并仅存储唯一图标。
正如我在 cmets 中提到的,您应该在单独的线程中询问您的第二个问题,但我建议您根据新的文件 mime 类型添加新的文件图标,而不是二进制图标数据。在这里你必须创建文件类型字典,确定文件类型等等..
TObjectList 中的重复项怎么办?
您可能知道,有generic 实现TObjectList - TObjectsList<T>。在您的示例中,您可以将TPersonList 定义为TObjectList<TPerson>,因此items 属性始终返回TPerson 对象实例。
现在,带有列表的通用任务 - 列表排序。看看TObjectList<T>/TList 的Sort() 方法。它有2个重载方法。其中之一是默认值,第二个采用Comparer 作为参数。实际上,第一种方法也使用了一个比较器——默认比较器。
所以比较器是IComparer<T> 接口的实现,它有唯一的方法-function Compare(l,r : T):integer;通常在调用Sort() 方法之前,您在运行时将这个排序比较器定义为匿名方法。使用匿名方法,您总是知道如何比较两个 T 类型的对象,然后您可以确定它们中的哪一个比其他对象“更大”,并且应该是列表中的第一个。
所以你在列表中搜索重复项时遇到的情况相同。但现在你必须确定 2 个对象是否相等。
假设您有 personList : TPersonList ,其中包含 TPerson 实例。例如,每个人都有姓名、姓氏、出生日期和身份证。
当然,默认比较器对如何比较 2 人一无所知。但是您可以提供新的比较器知道。例如,假设 2 个对象相等,如果它们的 ID 相等;
TPerson = class(TObject)
strict private
FName : string;
FSurname : string;
FDateOfBirth : TDateTime;
FId : string; {passport number or something else}
public
constructor Create(aID : string; aDoB : TDateTime);
property Name : string read FName write FName;
property Surname : string read FSurname write FSurname;
property DateOfBirth : TDateTime read FDateOfBirth;
property ID : string read FId;
end;
TPersonList = class(TObjectList<TPerson>)
public
constructor Create();
end;
TPerson 构造函数是常用的:
constructor TPerson.Create(aID: string; aDoB: TDateTime);
begin
inherited Create();
FID := aId;
FDateOfBirth := aDoB;
end;
现在我们必须写TPersonList 构造函数。如您所见,TObejctList 构造函数几乎没有重载。其中之一具有Comparer 参数。它将aComparer 保存到FComparer 字段。现在,看看Contains 方法。它发现列表是否已经包含对象。它使用IndexOf 方法。所以如果返回的 index = 0 那么 list 包含我们的对象。
所以现在我们的任务是在TPersonList 构造函数中定义新的比较器。我们应该定义比较方法,然后创建比较器对象并将其传递给列表构造函数。
constructor TPersonList.Create();
var comparer : IComparer<TPerson>;
comparison : TComparison<TPerson>;
begin
comparison := function(const l,r : TPerson):integer
begin
if l.ID = r.id then exit(0)
else if l.ID > r.ID then exit(-1)
else exit(1);
end;
comparer := TComparer<TPerson>.Construct(comparison);
inherited Create(comparer);
end;
为了测试我们的代码,让我们将一些人添加到列表中。
procedure TForm2.FormCreate(Sender: TObject);
var persons : TPersonList;
function AddPerson(id : string; date : TDateTime):boolean;
var p : TPerson;
begin
p := TPerson.Create(id, date);
result := not persons.Contains(p);
if result then
persons.Add(p)
else begin
ShowMessage('list already contains person with id = ' + id);
p.Free();
end;
end;
begin
persons := TPersonList.Create();
try
AddPerson('1', StrToDate('01.01.2000'));
AddPerson('2', StrToDate('01.01.2000'));
AddPerson('3', StrToDate('01.01.2000'));
AddPerson('2', StrToDate('01.01.2000')); // we will get message here.
finally
persons.Free();
end;
end;
所以,这是确定TList(或其后代)是否包含对象的常用方法。