【问题标题】:Cannot compile constrained generic method无法编译受约束的泛型方法
【发布时间】:2017-06-01 13:08:41
【问题描述】:

长话短说:以下代码无法在 Delphi 10.1 Berlin(更新 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).

为了规避这些,我可以转换TClass(T)(用于#1),如LU RD's answer here 中所述(尽管据说这个错误已经在XE6 中修复),并且T(TSomeComponent.Create(nil, AComponentString))(对于#2)。虽然,我对使用显式类型转换感到不舒服。

有没有更好的办法?编译器不应该认识到TTComponent 类型,因为我明确限制了它吗?


起初,我尝试将泛型函数的实现声明为接口:

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

但这以错误告终

E2029: ',', ';'或 '>' 预期但 ':' 找到

【问题讨论】:

  • “编译器不应该识别出 T 是 TComponent 类型,因为我明确地限制了它吗?”不,不会的。泛型约束不解析类型。它只是帮助编译器防止使用非约束类型的泛型类型或过程。看我的回答:stackoverflow.com/questions/43679740/…

标签: delphi generics constraints delphi-10.1-berlin generic-constraints


【解决方案1】:

这在我遇到的任何版本的 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(也许还有一个所有者)。或者也许他可以完全没有它。
猜你喜欢
  • 1970-01-01
  • 2015-02-08
  • 1970-01-01
  • 2016-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-19
  • 2012-06-05
相关资源
最近更新 更多