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

Leo*_*eon 5 delphi generics

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

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

好吧,这是代码:

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

  function Contains<AItem: T>: Boolean;
end;
Run Code Online (Sandbox Code Playgroud)

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

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

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

TMyRecordArray = TMyArray<TMyRecord, TMyRecordComparer>;  
Run Code Online (Sandbox Code Playgroud)

有了最后一个声明,我得到以下错误:E2515类型参数'T'与类型'System.Generics.Defaults.TComparer \'不兼容。

任何想法如何解决这个问题?

Ste*_*nke 7

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

TMyArray<T; C: class, constructor, IComparer<T>> = record
Run Code Online (Sandbox Code Playgroud)

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

同样,首先,在问题中发布代码后,您还将收到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;
Run Code Online (Sandbox Code Playgroud)

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

function Contains(AItem: T): Boolean;
Run Code Online (Sandbox Code Playgroud)


Dav*_*nan 6

问题是约束的语法:

TMyArray<T,C: TComparer<T>>
Run Code Online (Sandbox Code Playgroud)

这既约束TCTComparer<T>

相反,您需要这样做:

TMyArray<T; C: TComparer<T>>
Run Code Online (Sandbox Code Playgroud)

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