[英]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.