Delphi泛型:如何规范"引用自己类型的类"

gwi*_*man 4 delphi generics collections copy

在Delphi XE2中,我想编写一个泛型集合类来操作必须具有Copy(owntype)方法的对象,但我无法弄清楚如何最好地声明它.

我想要这样的例子(一个项目的集合,为简单起见):

//------ Library ------
Type
  TBaseCopyable = class
    S: string;
//    procedure Copy(OtherObject: TBaseCopyable); overload;
    procedure Copy(OtherObject: TBaseCopyable); virtual;
  end;

  MyCollection<T: TBaseCopyable, constructor> = class
    TheItem: T;
    procedure SetItem(AItem: T); 
    function  GetItem: T;
  end;

[...]

function MyCollection<T>.GetItem: T;
Var
  NewItem: T;
begin
  NewItem := T.Create;
  NewItem.Copy(TheItem);
  Result := NewItem;
end;


//------ Usage ------
Type
  TMyCopyable = class(TBaseCopyable)
    I: integer;
//  procedure Copy(OtherObject: TMyCopyable); overload;
    procedure Copy(OtherObject: TMyCopyable); override;
  end;

[...]
  Col: MyCollection<TMyCopyable>;
Run Code Online (Sandbox Code Playgroud)

关键问题是在Col中,我需要MyCollection的通用实现来查找TMyCopyable.Copy.不出所料,过载或虚拟都不能完成工作:

  • 有了重载,代码会编译,但MyCollection.GetItem会找到TBaseCopyable.Copy,而不是TMyCopyable.Copy.
  • 使用virtual/override时,由于两个Copy声明的签名不匹配,因此无法编译.

所以我想我需要在TBaseCopyable的规范中以某种方式使用泛型,可能代替继承.但我不确定如何,主要是因为我不特别需要将类型参数提供给TBaseCopyable,我只需要复制参数类型以通用方式引用"它自己类的类型".

想法?谢谢!

Rem*_*eau 6

转换TBaseCopyable为Generic类并将其Generic类型应用于Copy(),然后TMyCopyable可以覆盖它,例如:

type
  TBaseCopyable<T> = class
    S: string;
    procedure Copy(OtherObject: T); virtual;
  end;

  MyCollection<T: TBaseCopyable<T>, constructor> = class
    TheItem: T;
    procedure SetItem(AItem: T);
    function  GetItem: T;
  end;
Run Code Online (Sandbox Code Playgroud)

type
  TMyCopyable = class(TBaseCopyable<TMyCopyable>)
    I: integer;
    procedure Copy(OtherObject: TMyCopyable); override;
  end;
Run Code Online (Sandbox Code Playgroud)

或者,只做相同的事情TPersistent.Assign()(因为它不使用泛型):

type
  TBaseCopyable = class
    S: string;
    procedure Copy(OtherObject: TBaseCopyable); virtual;
  end;

  MyCollection<T: TBaseCopyable, constructor> = class
    TheItem: T;
    procedure SetItem(AItem: T);
    function  GetItem: T;
  end;
Run Code Online (Sandbox Code Playgroud)

type
  TMyCopyable = class(TBaseCopyable)
    I: integer;
    procedure Copy(OtherObject: TBaseCopyable); override;
  end;

procedure TMyCopyable.Copy(OtherObject: TBaseCopyable);
begin
  inherited;
  if OtherObject is TMyCopyable then
    I := TMyCopyable(OtherObject).I;
end;
Run Code Online (Sandbox Code Playgroud)

  • 真棒!谢谢!我不确定我会发现这种通用语法,但是当然我现在已经看到它了.并且优于非泛型版本,如在非通用版本中,编译器不强制将OtherObject强制为所需类型. (2认同)