如何将预先存在的函数分配给 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不适用于您目前的情况。
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不适用于您目前的情况。