11

我想为泛型类定义一个类类型(类型别名)。我想这样做,以便单元 b 的用户可以在不使用单元 a 的情况下访问 TMyType。我有这样的单位:

unit a;
interface
type
  TMyNormalObject = class
    FData: Integer;
  end;
  TMyType<T> = class
    FData: <T>;
  end;
implementation
end.

unit b;
interface
type
  TMyNormalObject = a.TMyNormalObject;  // works
  TMyType<T> = a.TMyType<T>; // E2508 type parameters not allowed on this type
implementation
end.

我已经找到了一个我不喜欢的可能的解决方法,因为它可能会引入难以找到的错误:

TMyType<T> = class(a.TMyType<T>); 

这种方法的问题在于它引入了一个新的类类型,并且 a.TMyType 实例不是 b.TMyType (而 a.TMyNormallClass 是 b.TMyNormalClass ,反之亦然 - 它们指的是同一个类)。

4

2 回答 2

11

当前无法为泛型类声明类类型。

有关详细信息,请参阅QC76605还有下面的更新。

例子 :

TMyClass<T> = class
end;
TMyClassClass<T> = class of TMyClass<T>; //E2508 type parameters not allowed on this type

提出的解决方法如下所示:

TMyIntClass = TMyType<Integer>;
TMyIntClassClass = Class of TMyIntClass;

但是正如评论的那样,这将破坏泛型的整个想法,因为必须为每个泛型实例化该类。

这里还有一个链接,指向生成泛型类型的专用子类的类似解决方法:derive-from-specialized-generic-types。在这种情况下,它看起来像这样:

TMySpecialClass = Class(TMyType<Integer>);

更新 :

RM提出的解决方法:

TMyType<T> = class(a.TMyType<T>);

可以使用以下方案实现类型安全:

unit Unita;
interface
type
  TMyType<T> = class
    Constructor Create;
  end;

implementation

uses
  Unitb;

constructor TMyType<T>.Create;
begin
  Inherited Create;
  //WriteLn( Self.QualifiedClassName,' ',Unitb.TMyType<T>.QualifiedClassName);
  Assert(Self.QualifiedClassName = Unitb.TMyType<T>.QualifiedClassName);
end;

end.

unit Unitb;

interface

uses Unita;

type
  TMyType<T> = class(Unita.TMyType<T>);
implementation
end.

Project Test;
{$APPTYPE CONSOLE}    
uses
  System.SysUtils,
  Unita in 'Unita.pas',
  Unitb in 'Unitb.pas';

var
  t1 : Unita.TMyType<Integer>;
  t2 : Unitb.TMyType<Integer>;
  t3 : TMyType<Integer>;    
begin
  try
    //t1 := Unita.TMyType<Integer>.Create;  //Exception EAssertionFailed !!
    t2 := Unitb.TMyType<Integer>.Create;
    t3 := TMyType<Integer>.Create;
    ReadLn;
  finally
    //t1.Free;
    t2.Free;
    t3.Free;
  end;
end.

创建泛型类时,会进行测试以检查创建的类是否派生自单元 b 中声明的类型。从而检测到所有从单元 a 创建此类的尝试。

更新 2:

为了清楚起见,对泛型类的引用“ class of type<T>”是不可能的,但是泛型类的副本是可以的。

于 2012-04-08T07:34:57.083 回答
0

由于无法为泛型类声明“类型别名”,因此这是使用接口的解决方案。

unit UnitA;

interface  

Uses UnitB; 

type
  TMyType<T> = class(TInterfacedObject,ITMyType<T>)
    FData : T;
    Constructor Create( aV : T);
  end;

implementation

constructor TMyType<T>.Create( aV : T);
begin
  Inherited Create;
  FData := aV;
  WriteLn( Self.QualifiedClassName);
end;

end.

unit UnitB;

interface

type
  ITMyType<T> = Interface
  End;

implementation

end.

program Test;
{$APPTYPE CONSOLE}
uses
  UnitA in 'UnitA.pas',
  UnitB in 'UnitB.pas';

var
  it1 : ITMyType<Integer>;
begin
  it1:= TMyType<Integer>.Create(1);
  ReadLn;
end.
于 2012-04-09T11:57:45.630 回答