简体   繁体   English

是否可以为通用 class 创建类型别名

[英]Is it possible to create a type alias to a generic class

I would like to define a class type (type alias) for a generic class. I would like to do this so users of unit b can have access to TMyType without using unit a.我想为通用 class 定义一个 class 类型(类型别名)。我想这样做,以便单元 b 的用户可以访问 TMyType 而无需使用单元 a。 I have units like this:我有这样的单位:

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.

I already found a possible workaround, which I don't like because it can introduce hard to find bugs:我已经找到了一个可能的解决方法,但我不喜欢它,因为它会引入难以发现的错误:

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

The problem with this approach is that it introduces a new class type and an a.TMyType instance is not a b.TMyType (while a.TMyNormallClass is a b.TMyNormalClass and vice versa - they are referring to the same class).这种方法的问题在于它引入了一个新的 class 类型,并且 a.TMyType 实例不是 b.TMyType(而 a.TMyNormallClass 是 b.TMyNormalClass,反之亦然 - 它们指的是同一个类)。

It's currently not possible to declare a class type for a generic class. 目前无法 为通用 class 声明 class 类型。

See QC76605 for more information.有关详细信息,请参阅QC76605 Also the update below.还有下面的更新。

Example:例子:

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

The workaround that is presented looks like this:提供的解决方法如下所示:

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

But as commented, that would defeat the whole idea of generics, since the class would have to be subclassed for every generic instantiation.但正如所评论的那样,这将打败 generics 的整个想法,因为 class 必须为每个通用实例进行子类化。

Here is also a link to a similar workaround on generating a specialized subclass of a generic type: derive-from-specialized-generic-types .这里还有一个链接,指向生成通用类型的专用子类的类似解决方法: derive-from-specialized-generic-types In this case it would look like this:在这种情况下,它看起来像这样:

TMySpecialClass = Class(TMyType<Integer>);

Update:更新:

The workaround proposed by RM: RM提出的解决方法:

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

can be implemented with type safety using following scheme:可以使用以下方案实现类型安全:

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.

When creating the generic class, a test is made to check that the created class is derived from the type declared in unit b.创建泛型 class 时,进行测试以检查创建的 class 是否派生自单元 b 中声明的类型。 Thereby all attempts to create this class from unit a is detected.从而检测到从单元 a 创建此 class 的所有尝试。

Update 2:更新 2:

Just to be clear, a reference to a generic class, " class of type<T> " is not possible, but a copy of a generic class is fine.需要明确的是,对通用 class 的引用,“ class of type<T> ”是不可能的,但是通用 class 的副本是可以的。

Since it is not possible to declare a "type alias" for a generic class, here is a solution using an interface .由于无法为通用 class 声明“类型别名”,因此这里是使用interface的解决方案。

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.
type  
    TMyArrOfT<T> = array of T;  
    TMyIntegers = TMyArrOfT<integer>;  

procedure x;  
var  
   t4: TMyIntegers;  
begin  
   t4 := [1,3,5,7,11];   //...
   for var i:integer := Low(t4) to High(t4) do  
      Memo1.Lines.Add(t4[i].ToString);  
end;  


type
    TMyArrOfT<T> = array of T;
    TMyButtons  = TMyArrOfT<TButton>;

procedure TForm1.Button1Click(Sender: TObject);
var
   t4: TMyButtons;
begin
   t4                 := [Button1, Button1, Button1, Button1, Button1]; // ...
   for var i: integer := Low(t4) to High(t4) do
      Memo1.Lines.Add(t4[i].Caption );
 end;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM