无法编译约束通用方法
长话短说:下面这段代码不能编译Delphi 10.1柏林(更新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;
几个错误消息从编译器发出:
-
E2015:操作员不适用于此的操作数类型
上线
if T = TSomeComponent then
和 -
E2010不兼容类型 - 'T'和'TSomeComponent'
on line
Result := TSomeComponent.Create(nil, AComponentString)
。
为了规避这些,我能投TClass(T)
(#1),如LU RD's answer here描述(尽管这是说,这个漏洞已经被固定在XE6),并T(TSomeComponent.Create(nil, AComponentString))
(#2 )。尽管使用明确的类型转换我感到不舒服。
有什么更好的办法吗?编译器是否应该认识到,T
的类型是TComponent
,因为我明确地约束了它?
起初,我试图声明泛型函数的实现,就像它的界面:
function TTest.BuildComponent<T: TComponent>(const AComponentString: String): T;
但是,这结束了与错误
E2029:”, '' ;”或'>'预期但是':'找到
这不会在我遇到的任何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(也可能是一个所有者)。或者也许他可以完全没有它。 –
“编译器不应该认识到,T是TComponent类型的,因为我明确地约束了它?”不,它不会。通用约束不解析类型。它只是帮助编译器*阻止*使用通用类型或过程,而不是约束类型。看到我的回答:https://stackoverflow.com/questions/43679740/test-if-an-interface-equals-a-type-parameter/43681952#43681952 –