如何在Delphi中将TComparer <t>类传递给泛型?

时间:2019-05-29 08:13:45

标签: delphi generics

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

然后,我决定像类型参数一样传递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 \'不兼容。

有什么办法解决这个问题吗?

2 个答案:

答案 0 :(得分:7)

虽然David的答案解决了编译错误的问题,但实际上我会使用其他约束:

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

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

另外,首先,在问题中粘贴代码,您将收到W1010警告,这意味着您缺少TMyRecordComparer.Compare方法的替代(以及它的const)。如果您是从TComparer<T>继承而来的,因为这是通过虚拟抽象方法实现的IComparer<T>,则需要这样做。

您使用.Default的想法也将不起作用,因为这会为类型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;

答案 1 :(得分:6)

问题在于约束的语法:

TMyArray<T,C: TComparer<T>>

这将TC都约束为TComparer<T>

相反,您需要这个:

TMyArray<T; C: TComparer<T>>

documentation提供了各种语法选项的示例。