私は現在、次のようなタイプの汎用リストを使用しています。
List: TList<TPoint>;
List
代わりに、3 つの座標を持つ点を保持できるようにしたいと思います。
type
TPoint3D = record
x, y, z: Integer;
end;
次のように宣言したいと思います。
List: TList<TCanBeEitherTPointOrTPoint3D>;
当然、これは機能しませんが、何が機能するかはわかりません。
私は現在、次のようなタイプの汎用リストを使用しています。
List: TList<TPoint>;
List
代わりに、3 つの座標を持つ点を保持できるようにしたいと思います。
type
TPoint3D = record
x, y, z: Integer;
end;
次のように宣言したいと思います。
List: TList<TCanBeEitherTPointOrTPoint3D>;
当然、これは機能しませんが、何が機能するかはわかりません。
Delphi は、異種の型のリストをサポートしていません。すべての潜在的な値を単一の型で表現できなければなりません。これを行う 1 つの方法は、すべての異なる型を 1 つの判別共用体に結合することです。
type
TPointUnion = record
case NumDimensions: Integer of
2: (p2: TPoint);
3: (p3: TPoint3D);
end;
次に、そのタイプのリストを宣言できます。
var
List: TList<TPointUnion>;
タイプの値をリストに追加できますTPointUnion
。その型の値を作成するには、単純にNumDimensions
フィールドを割り当ててから、対応するp2
orp3
フィールドを割り当てます。このような値を読み取る場合は、フィールドをチェックしNumDimensions
て、有効な値を保持しているポイント フィールドを見つけます。実際には、p2
は常に安全に使用できます。これは、そのフィールドが の対応するフィールドとオーバーラップするためですp3
。
別の方法として、 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;
この方法でパフォーマンスが向上するかどうかは正確にはわかりませんが、メモリ使用量は同じになります。
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 は、参照ではなく、値として渡されます (つまり、値がコピーされます)。