无法编译受限泛型方法。

4

长话短说:下面这段代码在 Delphi 10.1 Berlin (Update 2) 中无法编译。

interface

uses
  System.Classes, System.SysUtils;

type
  TTest = class(TObject)
  public
    function BuildComponent<T: TComponent>(const AComponentString: String): T;
  end;

  TSomeComponent = class(TComponent)
  public
    constructor Create(AOwner: TComponent; const AString: String); reintroduce;
  end;

implementation

{ TTest }

function TTest.BuildComponent<T>(const AComponentString: String): T;
begin
  if T = TSomeComponent then
    Result := TSomeComponent.Create(nil, AComponentString)
  else
    Result := T.Create(nil);
end;

{ TSomeComponent }

constructor TSomeComponent.Create(AOwner: TComponent; const AString: String);
begin
  inherited Create(AOwner);
end;

编译器发出了几个错误信息:

  1. E2015: 操作符不适用于此操作数类型

    在代码行 if T = TSomeComponent then 上和

  2. E2010 不兼容的类型 - 'T' 和 'TSomeComponent'

    在代码行 Result := TSomeComponent.Create(nil, AComponentString) 上。

为了避免这些问题,我可以进行强制类型转换,如 #1 中的 TClass(T)(参见LU RD在此处的答案,尽管它已经被说过这个bug已经在XE6中修复了),以及 #2 中的 T(TSomeComponent.Create(nil, AComponentString))。虽然如此,但是使用显式类型转换让我感到不舒服。

有没有更好的方法?编译器难道不能识别TTComponent类型吗,因为我明确地约束了它吗?


起初,我试图像接口一样声明泛型函数的实现:

function TTest.BuildComponent<T: TComponent>(const AComponentString: String): T;

但是这最终导致了错误

E2029: 期望使用 ','、';' 或 '>',但发现了 ':'


1
“编译器不应该认识到,因为我明确地对T进行了约束,所以T是TComponent类型吗?” 不会。通用约束不会解决类型问题。它只是帮助编译器防止使用与约束类型不同的通用类型或过程。请参见我的答案:https://stackoverflow.com/questions/43679740/test-if-an-interface-equals-a-type-parameter/43681952#43681952 - Dave Olson
1个回答

4

在我遇到的所有Delphi版本中,这段代码都无法编译。你需要进行一些类型转换来让编译器正常工作:

function TTest.BuildComponent<T>(const AComponentString: String): T;
begin
  if TClass(T) = TSomeComponent then
    Result := T(TSomeComponent.Create(nil, AComponentString))
  else
    Result := T(TComponentClass(T).Create(nil));
end;

话虽如此,我认为我可能更喜欢:

if TClass(T).InheritsFrom(TSomeComponent) then

代替那个等式测试。

即使如此,试图将具有不同参数的新构造函数拼接到基于虚拟构造函数的类中,对我来说看起来像是一场灾难的预谋。


我也更喜欢使用InheritsFrom测试。而且,我不会为新组件提供不同的构造函数,我会改用属性。然后,BuildComponent可能不再需要成为通用方法,他可以只传递一个TComponentClass(也许还有一个所有者)。或者,他完全可以不使用它。 - Rudy Velthuis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接