如何将预先存在的函数分配给 TComparison<T>?

How do I assign a pre-existing function to a TComparison<T>?

program Project55;    
{$APPTYPE CONSOLE}
uses
  System.Generics.Defaults;

type
  TestRec<T> = record
    Compare: TComparison<T>;
    CompareI: IComparer<T>;
  end;

var
  TRI: TestRec<Integer>;

begin
  TRI.CompareI:= TComparer<Integer>.Default;
  TRI.Compare:= TRI.CompareI.Compare;  //E2035 Not enough actual parameters
  TRI.Compare:= @TRI.CompareI.Compare; //E2035 Not enough actual parameters
end.

我知道我可以将函数体分配为匿名函数,但为什么我不能分配一个现有函数?

当然可以使用以下方法,但这太愚蠢了:

  TRI.Compare:= function(const L,R: integer): Integer
  begin
    Result:= TRI.CompareI.Compare(L,R);
  end;

PS。我正在使用 Delphi XE7,但我怀疑版本问题。

您尝试执行此分配失败,因为无法将 接口方法 分配给 方法引用 变量。语言根本不允许这样做。这些类型与赋值不兼容。有效的赋值源是匿名方法、classes 的方法(实例或 class)和单元作用域过程。

在其他答案中可以看到的技巧都取决于对实现细节的深入了解。这意味着它们可能会发生变化。但是就语言而言,您的尝试是不允许的。

知道 IComparer<T> 是一个只有一个方法的接口,与 TComparison<T> 具有相同的签名,并且匿名方法只是一个方法的接口,您可以执行以下操作。

IComparer<Integer>(TRI.Compare) := TRI.CompareI;

我在 Spring4D 中使用该技巧来避免围绕 TComparison<T> 创建包装对象以作为 IComparer<T> 传递,因为它们是二进制兼容的。

匿名方法不完全是方法指针。它们被实现为具有单一方法的接口 "Invoke".

可以从匿名方法中提取方法指针,但据我所知,它依赖于匿名方法的当前实现细节,并且可能会在 delphi 的未来版本中发生变化。换句话说,我会反对它。这是逐字摘自 Barry Kelly 的 post here。 (这比我在这里更全面地涵盖了主题)

procedure MethRefToMethPtr(const MethRef; var MethPtr);
type
  TVtable = array[0..3] of Pointer;
  PVtable = ^TVtable;
  PPVtable = ^PVtable;
begin
  // 3 is offset of Invoke, after QI, AddRef, Release
  TMethod(MethPtr).Code := PPVtable(MethRef)^^[3];
  TMethod(MethPtr).Data := Pointer(MethRef);
end;

根据您的示例,我建议将此作为替代方案

type
  TestRec<T> = record
    CompareI: IComparer<T>;
    function Compare(const L, R : T) : Integer;
  end;
[...]
function TestRec<T>.Compare(const L, R : T) : Integer;
begin
  Result := CompareI.Compare(L,R);
end;

但是,它may/may不适用于您目前的情况。