Delphi XE: Can I call virtual constructors with parameters from a classtype-constrained generic type without resigning to hacks?
我正在尝试为复合控件构建一个通用祖先。最初的想法是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | type TCompositeControl<TControl1: TControl; TControl2: TControl> = class(TWinControl) private FControl1, FControl2: TControl; public constructor Create(AOwner: TComponent); override; end; TLabelAndEdit = TCompositeControl<TLabel, TEdit>; // simple example for illustration only constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent); begin inherited Create(AOwner); FControl1 := TControl1.Create(Self); FControl2 := TControl2.Create(Self); end; |
您可能已经知道,这将触发编译器错误 E2568: Can\\'t create new instance without CONSTRUCTOR constraint in type parameter declaration。然而,添加
将模板转换为
1 2 3 | ... FControl1 := TControl(TControl1).Create(Self); ... |
...但它会在运行时导致访问冲突。
一个可能可行的技巧是通过 RTTI 调用构造函数,但我认为这是一个相当肮脏的解决方案。
另一个基本有效的技巧是使用类类型变量作为中间体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | type TControlClass = class of TControl; constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent); var lCtrlClass1, lCtrlClass2: TControlClass; begin inherited Create(AOwner); lCtrlClass1 := TControl1; FControl1 := lCtrlClass1.Create(Self); lCtrlClass2 := TControl2; FControl2 := lCtrlClass2.Create(Self); end; |
有更清洁的解决方案吗?另外,有人可以向我解释一下为什么 classtype-constraint 不足以直接在类型参数上调用虚拟构造函数吗?
你的类型转换不好:
1 | FControl1 := TControlClass(TControl1).Create(Self); |
似乎最新的 delphi 版本(西雅图)不再发出此编译器错误。我在应用程序中遇到了同样的问题,但只有在使用 DelphiXe8 编译而不是使用 delphi Seattle
时
另一种语法是
1 2 3 4 5 | FControl1 := TControl1(TControl1.NewInstance); // get memory for object FControl1.Create(self); // call type-specific constructor FControl2 := TControl2(TControl2.NewInstance); // get memory for object FControl2.Create(self); // call type-specific constructor |
这在 Delphi 的 Classes.pas::CreateComponent 中使用
我只是无法决定哪个选项最不丑!
如果你的类使用没有参数的构造函数(如 TObject),我建议按照编译器所说的去做:
"在类型参数声明中添加构造函数约束"
它应该看起来像这样:
TCompositeControl < Control1:TControl,构造函数; TControl2:TControl,构造函数 > = Class(TWinControl)
如果这样做,您应该能够对泛型类型的构造函数进行必要的调用。
Howether,我不知道,如果它与需要参数的构造函数一起使用。
如果可行,请告诉我们。