14.2.5 泛型类的类构造函数
当您为泛型类定义构造函数时,会出现一个非常有趣的情况。实际上,编译器会生成一个这样的构造函数,并为每个泛型类实例调用这个构造函数,即为使用泛型模板定义每个实际类型。这非常有趣,因为如果没有构造函数,在您的程序中要创建的每个泛型类的实例,要执行初始化代码将非常复杂。
例如,考虑一个具有一些类类型数据的泛型类。每个泛型类的实例也会获得这种类类型数据的实例。如果您需要为类类型数据分配初始值,则无法使用Unit初始化代码,因为在定义泛型类的单元中,您不知道将需要哪些实际类。
以下是一个泛型类的示例,其中使用类构造函数初始化DataSize
类字段,该示例摘自GenericClassCtor
示例:
type
TGenericWithClassCtor<T> = class
private
FData: T;
procedure SetData(const Value: T);
public
class constructor Create;
property Data: T read FData write SetData;
class var
DataSize: Integer;
end;
这是泛型类构造函数的代码,它使用内部字符串列表(有关实现细节,请参见完整源代码)来跟踪实际调用的类构造函数:
class constructor TGenericWithClassCtor<T>.Create;
begin
DataSize := SizeOf(T);
ListSequence.Add(ClassName);
end;
演示程序创建并使用了一对泛型类实例,并声明了第三个泛型类的数据类型,该数据类型由链接器删除:
var
GenInt: TGenericWithClassCtor<SmallInt>;
GenStr: TGenericWithClassCtor<string>;
type
TGenDouble = TGenericWithClassCtor<Double>;
如果您要求程序显示ListSequence字符串列表的内容,您将只会看到实际初始化的类型:
TGenericWithClassCtor<System.SmallInt>
TGenericWithClassCtor<System.string>
但是,如果您在不同的单元中基于相同的数据类型创建泛型实例,则链接器可能无法按预期工作,并且您将拥有多个相同类型的泛型类构造函数。
注解:解决这个问题并不容易。为了避免重复初始化,您可能需要检查类构造函数是否已执行。然而,总的来说,这个问题是泛型类的更全面限制的一部分,而链接器无法对其进行优化。
在这个示例的第二个单元中,我添加了一个名为Useless的过程,当取消注释时,它将突出显示该问题,并显示以下初始化序列:
TGenericWithClassCtor<System.string>
TGenericWithClassCtor<System.SmallInt>
TGenericWithClassCtor<System.string>