2009-06-30 84 views
2

我想写一个泛型类,其中包含一个通用的TObjectList < T>它应该只包含TItem的元素。TGenericClass <T>包含一个TObjectList <T>不能编译

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; 

这是错误的语法吗?顺便说一下:TGenericClass < T:class> compiles,但是然后List中的Items不再是TItem,这就是我不想要的。

回答

6

这是带D2009编译器的known bug。它很可能很快就会被修复,无论是在2009年的更新或修补程序中,还是在Delphi 2010(Weaver)发布之后。在此之前,不幸的是,您需要某种解决方法。 :(

7

泛型类型可以有几个限制:

  • 类名,泛型类型必须是类的类的后代的。
  • 接口名称,泛型类型必须实现该接口。
  • 'class',泛型类型必须是类(这不能与类名组合)。
  • '记录',泛型类型必须是记录。
  • '构造函数',有点模糊,但您可以创建泛型类型的实例。

如果您创建使用其他泛型的泛型,则需要复制约束条件,否则将无法工作。在你的情况下,TObjectList有类约束。这意味着,你的T也需要这个约束。

不幸的是,这不能与命名的类约束相结合。

所以我建议你使用一个接口,这可以结合:

type 
    IItem = interface end; 
    TItem = class (TInterfacedObject, IItem) end; 
    TGenericClass<T: class, IItem> = class 
    private 
    FSimpleList: TList<T>; 
    FObjectList: TObjectList<T>; 
    end; 

此外,你应该让你的领域其他私人任何人都可以更改。

3

我喜欢GameCat的答案(给它+1)为限制类的描述。

我有你的代码工作的轻微修改。需要注意的是,因为你给了一个约束说,T必须是TItem的后代,可以真正地宣布链表类为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; 

添加是如何访问对象列表的示例。事实证明,你可以通过项目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应该没问题。

+0

是的,这会起作用,但它正是那种引入了通用列表的丑陋代码,可以让我们摆脱困境。这是一个纯粹而简单的编译器错误。它已被团队认可,并且很快就会被修复。像这样的解决方法暂时可行,但不要太过分了。 – 2009-06-30 12:35:33

相关问题