我正在尝试编写一个包含通用TObjectList<的泛型类。 T>它应该只包含TItem的元素。
uses
Generics.Collections;
type
TItem = class
end;
TGenericClass<T: TItem> = class
public
SimpleList: TList<T>; // This compiles
ObjectList: TObjectList<T>; // This doesn't compile: Compiler complaints that "T is not a class type"
end;
这是一个错误的语法吗? BTW:TGenericClass&lt; T:class&gt;编译,但列表中的项目不再是TItem,这是我不想要的。
答案 0 :(得分:7)
通用类型可以有几个约束:
如果您创建使用其他泛型的泛型,则需要复制约束,否则它将无效。在您的情况下,TObjectList具有类约束。这意味着,你的T也需要这个约束。
不幸的是,这不能与命名的类约束结合使用。
所以我建议你使用一个界面,这些可以合并:
type
IItem = interface end;
TItem = class (TInterfacedObject, IItem) end;
TGenericClass<T: class, IItem> = class
private
FSimpleList: TList<T>;
FObjectList: TObjectList<T>;
end;
此外,您应该将您的字段设为私有,否则任何人都可以更改它们。
答案 1 :(得分:7)
这是带有D2009编译器的known bug。它很可能很快就会被修复,无论是在2009年的更新或修补程序中,还是在Delphi 2010(Weaver)发布之后。在那之前,不幸的是,你需要某种解决方法。 :(
答案 2 :(得分:3)
我喜欢GameCat的答案(给它+1)来描述类约束。
我对您的代码进行了轻微修改。请注意,既然你给了一个约束来说T必须是TItem的后代,你实际上只需要将ObjectList声明为TObjectList<TItem>
- 这里不需要使用T.
或者,您可以创建排序代理。首先,请注意GameCat关于字段为私有的评论。
type
TGenericClass<T: TItem> = class
private
type
D = class(TItem); // Proxy to get your T into and object list
private
SimpleList: TList<T>;
ObjectList: TObjectList<D>; // Compiles now, but there is that type issue
public
procedure Add(Item: T); // No direct access to ObjectList
end;
添加是如何访问对象列表的示例。事实证明,您可以毫无困难地将Item传递给ObjectList.Add:
procedure TGenericClass<T>.Add(Item: T);
begin
ObjectList.Add(Item);
end;
我认为这可能是一个错误,所以要保护自己免受修复:
procedure TGenericClass<T>.Add(Item: T);
var
Obj: TObject;
begin
Obj := Item;
ObjectList.Add(D(Obj));
end;
考虑到你的情况,我会说TObjectList应该没问题。