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.TMyNormalClass は 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;

しかし、コメントしたように、ジェネリックのインスタンス化ごとにクラスをサブクラス化する必要があるため、ジェネリックのアイデア全体が無効になります。

ジェネリック型の特殊化されたサブクラスを生成するための同様の回避策へのリンクもここにあります: destroy-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 に答える