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); |
您可能已经知道,这将触发编译器错误 E2568: Can\\’t create new instance without CONSTRUCTOR constraint in type parameter declaration。然而,添加 constructor 约束并没有帮助,因为它意味着一个无参数的构造函数。
将模板转换为 TControl 使代码可编译:
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); |
有更清洁的解决方案吗?另外,有人可以向我解释一下为什么 classtype-constraint 不足以直接在类型参数上调用虚拟构造函数吗?
你的类型转换不好:TControl(TControl1).Create(Self)。这告诉编译器 TControl1 是 TControl 的一个实例,但我们知道它不是一个实例。这是一个类参考。将其类型转换为类引用类型:
1
|
FControl1 := TControlClass(TControl1).Create(Self);
|
- 啊,是的。接得好。说得通。
- 顺便说一句,您是否也知道为什么我不能将 FControl1 和 FControl2 分别声明为 TControl1 和 TControl2 ?如果我这样做了,我会在单元末尾收到编译器错误 E2010 Incompatible types: ‘TLabel’ and ‘TControl’。
- 不知道。我没有要测试的 Delphi 版本。如果这里还没有关于它的问题,请从这个问题中削减代码并将其作为一个新问题发布。
- 肯定会的。奇怪的是,到目前为止,我无法用比 TComponent-descendants 更简单的方法重现问题……无论如何,再次感谢原始答案!
似乎最新的 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 |
这在 Delphi 的 Classes.pas::CreateComponent 中使用
我只是无法决定哪个选项最不丑!
如果你的类使用没有参数的构造函数(如 TObject),我建议按照编译器所说的去做:
“在类型参数声明中添加构造函数约束”
它应该看起来像这样:
TCompositeControl < Control1:TControl,构造函数; TControl2:TControl,构造函数 > = Class(TWinControl)
如果这样做,您应该能够对泛型类型的构造函数进行必要的调用。
Howether,我不知道,如果它与需要参数的构造函数一起使用。
如果可行,请告诉我们。
- 请重新阅读问题。这特别是关于带有参数的构造函数,并且 constructor 约束不能与这些一起使用。
来源:https://www.codenong.com/9586626/