3

私は現在、次のようなタイプの汎用リストを使用しています。

List: TList<TPoint>;

List代わりに、3 つの座標を持つ点を保持できるようにしたいと思います。

type 
  TPoint3D = record 
    x, y, z: Integer;
  end;

次のように宣言したいと思います。

List: TList<TCanBeEitherTPointOrTPoint3D>;

当然、これは機能しませんが、何が機能するかはわかりません。

4

4 に答える 4

9

Delphi は、異種の型のリストをサポートしていません。すべての潜在的な値を単一の型で表現できなければなりません。これを行う 1 つの方法は、すべての異なる型を 1 つの判別共用体に結合することです。

type
  TPointUnion = record
    case NumDimensions: Integer of
      2: (p2: TPoint);
      3: (p3: TPoint3D);
  end;

次に、そのタイプのリストを宣言できます。

var
  List: TList<TPointUnion>;

タイプの値をリストに追加できますTPointUnion。その型の値を作成するには、単純にNumDimensionsフィールドを割り当ててから、対応するp2orp3フィールドを割り当てます。このような値を読み取る場合は、フィールドをチェックしNumDimensionsて、有効な値を保持しているポイント フィールドを見つけます。実際には、p2は常に安全に使用できます。これは、そのフィールドが の対応するフィールドとオーバーラップするためですp3

于 2013-03-27T21:56:36.533 に答える
1

別の方法として、 Rob が提案するようにバリアント パーツを含むレコードタイプの代わりに classe タイプを使用することもできます。

type
  TPoint2D = class(TObject)
    X: Integer;
    Y: Integer;
  end;

  TPoint3D = class(TPoint2D)
    Z: Integer;
  end;

var
  List: TList<TPoint2D>;

begin
  if List[I] is TPoint2D then
    TPoint2D(List[I]).X := 10
  else
    TPoint3D(List[I]).Z := 10;

この方法でパフォーマンスが向上するかどうかは正確にはわかりませんが、メモリ使用量は同じになります。

于 2013-03-28T05:44:30.333 に答える
0

System.RTTI.TValue が役立つ場合があります。

type
  tAnyList = tList<TValue>;  // Generic TList of TValue

procedure testTAnyList;
var
  tal: tAnyList;
  pt3d: TPoint3D;
  pt2d: TPoint2D;
begin
  // Init pt3d, pt2d here
  tal := tAnyList.Create;
  try
    tal.Add('Some Text');        // Store text
    tal.Add(16);                 // Some integer
    tal.Add(form1);              // Object
    tal.Add(tValue.From(pt3d));  // TPoint3D record
    tal.Add(tValue.From(pt2d));  // TPoint2D record
  finally
    tal.Free;
  end;
end;

レコードを使用する場合の注意: pt3d は、参照ではなく、値として渡されます (つまり、値がコピーされます)。

于 2013-03-29T10:49:07.063 に答える