【问题标题】:How to define a template for generic collection item?如何为通用集合项定义模板?
【发布时间】:2014-10-18 11:53:51
【问题描述】:

我正在尝试为通用列表定义我自己的项目类型。所有项目都需要有一个owner 属性。

type 
  TGenericCollection<TGenericCollectionItem: class> = class(TObjectList<TGenericCollectionItem>)
  protected
    procedure Notify(const Value: TGenericCollectionItem; Action: TCollectionNotification); override;
  public
    procedure Assign(Source: TGenericCollection<TGenericCollectionItem>); virtual;
  end;

  TGenericCollectionItem = class
  private
    FOwner: TGenericCollection<TGenericCollectionItem>;  //another class can change this value if it was declared in the same unit
  protected
    function GetOwner: TGenericCollection<TGenericCollectionItem>; virtual;
  public
    constructor Create; virtual;
    property Owner: TGenericCollection<TGenericCollectionItem> read GetOwner;
  end;

implementation

{ TGenericCollection<TGenericCollectionItem> }
procedure TGenericCollection<TGenericCollectionItem>.Assign(
  Source: TGenericCollection<TGenericCollectionItem>);
begin
  AddRange(Source.ToArray);
end;

procedure TGenericCollection<TGenericCollectionItem>.Notify(
  const Value: TGenericCollectionItem; Action: TCollectionNotification);
begin
  inherited;

  if (Action = cnAdded) then
  begin
    OutputDebugString(PChar(Value.ClassName)); // Debug Output: THandingItem Process GenericCollection.exe (2424)
    OutputDebugString(PChar(Self.ClassName));  // Debug Output: THandingList Process GenericCollection.exe (2424)
//    Value.FOwner := Self;  // Error: [dcc32 Error] Unit2.pas(46): E2003 Undeclared identifier: 'FOwner'
//    (Value as TGenericCollectionItem).FOwner := Self;   // Error: [dcc32 Error] Unit2.pas(46): E2003 Undeclared identifier: 'FOwner'
//    (Value as TGenericCollectionItem<T>).FOwner := Self;   // Undeclared identifier 'T'
  end;
end;

当我尝试更改 FOwner 值时,编译器会说 FOwner 是未声明的标识符。 THandingList 继承自 TGenericCollectionTHandingItem 继承自 TGenericCollectionItem

我做错了什么? Sample project


UPD:TGenericCollectionItem 已在代码示例中更改。


控制台应用:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  System.Generics.Collections;

type
  TGenericCollection<TGenericCollectionItem: class> = class(TObjectList<TGenericCollectionItem>)
  protected
    procedure Notify(const Value: TGenericCollectionItem; Action: TCollectionNotification); override;
  end;

  TGenericCollectionItem = class
  public
    Owner: TGenericCollection<TGenericCollectionItem>;
  end;

  procedure TGenericCollection<TGenericCollectionItem>.Notify(
    const Value: TGenericCollectionItem; Action: TCollectionNotification);
  begin
    inherited;

    if (Action = cnAdded) then
      Value.Owner := Self;
  end;

var
  GenericCollectionItem: TGenericCollectionItem;
  GenericCollection: TGenericCollection<TGenericCollectionItem>;
begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
    GenericCollection := TGenericCollection<TGenericCollectionItem>.Create;
    try
      GenericCollectionItem := TGenericCollectionItem.Create;
      GenericCollection.Add(GenericCollectionItem);
    finally
      GenericCollection.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

【问题讨论】:

  • 那是因为您在 TGenericCollectionItem&lt;T: class&gt; 类中声明了 FOwner,而不是在基类 TGenericCollectionItem 中(尚不知道)。此外,它目前是只读的。
  • TGenericCollectionItem 的通用参数是什么意思?当然这是错误的。你的设计还有一个致命的缺陷。一个项目可以是两个列表的成员。楼主是谁?
  • @TLama 好的。我已经更改了TGenericCollectionItem 类(请参阅有问题的代码)。但是编译器还是这么说的。
  • @DavidHeffernan 我不知道谁将成为所有者。可能是最后一个。我正在尝试在泛型中实现TCollectionTCollectionItem 功能。 TCollectionTCollectionItemSystem.Classes 单元中。
  • @DavidHeffernan 检查问题更新。

标签: delphi generics delphi-xe6


【解决方案1】:

哦,这令人困惑。您已将TGenericCollectionItem 用作通用参数名称和类型名称。在TGenericCollection 代码中,名称TGenericCollectionItem 指的是泛型类型参数,而不是同名的类。您对TGenericCollectionItem 的所有了解就是它是一个类。也就是说,它源自TObject。因此没有名为Owner 或确实FOwner 的成员。

改变

TGenericCollection<TGenericCollectionItem: class>

TGenericCollection<T: TGenericCollectionItem>

请注意,您可能需要转发声明 TGenericCollectionItem

更新:啊,由于 Delphi 泛型的设计缺陷,当相互引用的类之一是泛型时,前向声明将不起作用。见How to set a forward declaration with generic types under Delphi 2010?

【讨论】:

  • 谢谢。似乎这会奏效。但是现在我无法对TGenericCollectionItem 进行前向声明。类型“TGenericCollectionItem”尚未完全定义。
  • 我会做一个新的问题。
  • 不要提出新问题。在这里阅读我的答案stackoverflow.com/questions/25474503/…
  • 不一样。正确的解决方案在这里stackoverflow.com/questions/6055742/…
  • 是的,我在发布后意识到。泛型会踢你。我实际上解决这个问题的方式与那里的答案不同,但是你去吧。
猜你喜欢
  • 1970-01-01
  • 2012-02-05
  • 2015-01-17
  • 2022-08-19
  • 2018-09-16
  • 2016-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多