如何为通用集合项定义模板?

时间:2014-08-25 10:41:18

标签: delphi generics delphi-xe6

我试图为通用列表定义自己的项类型。所有项目都需要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.

1 个答案:

答案 0 :(得分:1)

哦,这令人困惑。您已将TGenericCollectionItem用作通用参数名称和类型名称。在TGenericCollection代码中,名称TGenericCollectionItem引用泛型类型参数,而不是同名的类。关于TGenericCollectionItem泛型参数的所有知识都是它是一个类。也就是说,它来自TObject。因此没有名为OwnerFOwner的成员。

更改

TGenericCollection<TGenericCollectionItem: class>

TGenericCollection<T: TGenericCollectionItem>

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

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