首页 > 解决方案 > 如何通过 TComparer类到Delphi中的泛型类型?

问题描述

我想创建具有某些功能的通用记录,包括搜索功能。为了执行这个搜索,我想传递一个自定义的比较器来比较项目。如果它是一个类,我可以在构造函数中传递它,但我想使用记录来避免创建或释放它。所以,我没有一个构造函数来初始化比较器。

然后我决定像 Type 参数一样传递 Comparer 类,当我需要比较器时,使用 TComparer.Default 创建比较器的实例。

好吧,这里是代码:

TMyArray<T,C: TComparer<T>> = record
  FComparer: IComparer<T>;
  Items: TArray<T>;

  function Contains<AItem: T>: Boolean;
end;

当我尝试以这种方式使用它时出现问题:

TMyRecord = record
  Score: Real;
  A: string;
  B: string;
end;

TMyRecordComparer = class(TComparer<TMyRecord>)
  function Compare(Left, Right: TMyRecord): Integer;
end;

TMyRecordArray = TMyArray<TMyRecord, TMyRecordComparer>;  

使用最后一个声明,我收到此错误:E2515 类型参数“T”与类型“System.Generics.Defaults.TComparer\”不兼容。

知道如何解决这个问题吗?

标签: delphigenerics

解决方案


虽然大卫的回答解决了编译错误的问题,但我实际上会使用不同的约束:

TMyArray<T; C: class, constructor, IComparer<T>> = record

这意味着C必须是一个具有无参数构造函数并实现IComparer<T>接口的类。这稍微放宽了约束,因为您不必继承比较器,System.Generics.Collections.TComparer<T>而只需实现所需的IComparer<T>接口。

此外,fwiw,使用您的问题中发布的代码,您将收到 W1010 警告,这意味着您缺少对您的TMyRecordComparer.Compare方法的覆盖(以及它的缺失const)。如果您从使用虚拟抽象方法TComparer<T>实现的继承,则需要这样做。IComparer<T>

您使用的想法.Default也行不通,因为该想法为 type 的比较器创建了默认实现T。但是您想使用您指定的自定义。

所以有了我上面写的约束,你可以做这样的事情(天真的非线程安全实现):

function TMyArray<T, C>.Contains<AItem>: Boolean;
begin
  if FComparer = nil then
    FComparer := C.Create;
  // ....
end;

最后但并非最不重要的一点是,我不确定您的Contains方法是否正确 - 您编写它的方式表明您要检查您的数组是否包含AItem类型T或子类型的类型元素(或者是否T是接口类型,实现T) - 我猜你打算写

function Contains(AItem: T): Boolean;

推荐阅读