【问题标题】:How to use TObjectList for arbitrary class type?如何将 TObjectList 用于任意类类型?
【发布时间】:2018-01-11 15:31:34
【问题描述】:

我对 Delphi 中的泛型仍然有些模糊,但我一直在广泛使用 TObjectList<>。现在我有一种情况,我有一个具有这样一个私有字段的基类,但需要为任意类创建,该类也继承自另一个基类。

为了澄清,我有两个基类:

type
  TItem = class;
  TItems = class;

  TItemClass = class of TItem;

  TItem = class(TPersistent)
  private
    FSomeStuffForAllIneritedClasses: TSomeStuff;
  end;

  TItems = class(TPersistent)
  private
    FItems: TObjectList<TItem>;
    FItemClass: TItemClass;
  public
    constructor Create(AItemClass: TItemClass);
    destructor Destroy; override;
    function Add: TItem;
    ...
  end;

这对类然后被进一步继承到更具体的类中。我希望为所有对象共享对象列表,而每个对象实际上在内部都拥有不同的类型。

type
  TSomeItem = class(TItem)
  private
    FSomeOtherStuff: TSomeOtherStuff;
    ...
  end;

  TSomeItems = class(TItems)
  public
    function Add: TSomeItem; //Calls inherited, similar to a TCollection
    procedure DoSomethingOnlyThisClassShouldDo;
    ...
  end;

现在的问题是在创建实际对象列表时。我正在尝试这样做:

constructor TItems.Create(AItemClass: TItemClass);
begin
  inherited Create;
  FItemClass:= AItemClass;
  FItems:= TObjectList<AItemClass>.Create(True);
end;

但是,代码洞察力抱怨这一点:

未声明的标识符AItemClass

更何况,编译器还有不一样的抱怨:

未声明的标识符TObjectList

在哪里,我确实在这个单元中使用了System.Generics.Collections

我在这里做错了什么,我应该怎么做?

【问题讨论】:

    标签: delphi generics inheritance delphi-10.1-berlin


    【解决方案1】:

    使TItems 通用:

    TItems<T: TItem, constructor> = class(TPersistent)
    private
      FItems: TObjectList<T>;
    public
      constructor Create;
      destructor Destroy; override;
      function Add: T;
      ...
    end;
    
    constructor TItems.Create;
    begin
      inherited Create;
      FItems:= TObjectList<T>.Create(True);
    end;
    
    function TItems<T>.Add: T;
    begin
      Result := T.Create;
      FItems.Add(Result);
    end;
    

    如果继承,只需输入正确的泛型参数即可:

    TSomeItems = class(TItems<TSomeItem>)
    public
      procedure DoSomethingOnlyThisClassShouldDo;
      ...
    end;
    

    【讨论】:

    • 看,我知道必须有另一种使用泛型的方法。让我试一试(当我有机会时)。
    • 当然值得一提的是,这需要在编译时知道项目类型,但有时并非如此。
    【解决方案2】:

    TObjectList 不适合以这种方式使用。它最初被定义为TObjectList&lt;TItem&gt; 的事实意味着它也希望您以这种方式创建它。它需要使用您打算创建它的精确类来定义。

    相反,只需使用TItem 创建它,然后每当您创建一个应该添加到此列表中的新项目时,然后您使用类类型创建它。任何时候您需要访问此列表中的项目时,只需即时投射它们即可。

    例如...

    Result:= FItemClass.Create;
    FItems.Add(Result);
    

    ...可以是 Add 函数的内容。

    【讨论】:

    • 从长远来看,您将需要一个虚拟构造函数来完成这项工作
    • @David 确实,但我把所有这些都省略了,因为它与问题无关。
    • 不是直接的,但这绝对是任何这样做的人都将面临的下一个障碍。这就是我留下有用评论的原因。
    猜你喜欢
    • 2022-01-21
    • 2011-03-26
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    相关资源
    最近更新 更多