我目前正在使用这样输入的通用列表:
List: TList<TPoint>;
我希望List
能够作为替代方案持有三个坐标的点:
type
TPoint3D = record
x, y, z: Integer;
end;
我想宣布这样的事情:
List: TList<TCanBeEitherTPointOrTPoint3D>;
当然这不起作用,但我不知道它会起作用!
答案 0 :(得分:8)
Delphi不支持异类类型列表。您必须能够使用单一类型表示所有潜在值。一种方法是将所有不同的类型加入一个有区别的联合:
type
TPointUnion = record
case NumDimensions: Integer of
2: (p2: TPoint);
3: (p3: TPoint3D);
end;
然后您可以声明该类型的列表:
var
List: TList<TPointUnion>;
您可以将类型TPointUnion
的值添加到列表中。要构建该类型的值,只需指定NumDimensions
字段,然后指定相应的p2
或p3
字段即可。读取此类值时,请检查NumDimensions
字段以发现哪个点字段包含有效值。实际上,p2
始终可以安全使用,因为其字段与p3
的相应字段重叠。
答案 1 :(得分:1)
作为替代方案,您可以使用classe类型而不是record type with variant parts作为Rob suggests:
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;
我不确切知道这种方法是否会表现更好,但内存使用情况会相同。
答案 2 :(得分: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将作为值传递(即它的值将被复制),而不是通过引用传递。
答案 3 :(得分:0)
program MultiClass;
{$APPTYPE CONSOLE}
uses
SysUtils, Generics.Defaults, Generics.Collections;
type
TPoint2D = class
x, y: integer;
constructor create(x, y: integer);
end;
TPoint3D = class
x, y, z: integer;
constructor create(x, y, z: integer);
end;
TPointSelector = (ePoint2D, ePoint3D);
TPoint2DOrTPoint3D = class
select: TPointSelector;
obj: Pointer;
constructor create(myClass: TPoint2D); overload;
constructor create(myClass: TPoint3D); overload;
constructor create(x, y: integer); overload;
constructor create(x, y, z: integer); overload;
destructor Destroy; override;
end;
Constructor TPoint2D.create(x: integer; y: integer);
begin
self.x := x;
self.y := y;
end;
Constructor TPoint3D.create(x: integer; y: integer; z: integer);
begin
self.x := x;
self.y := y;
self.z := y;
end;
constructor TPoint2DOrTPoint3D.create(x, y: integer);
begin
select := ePoint2D;
obj := TPoint2D.create(x, y);
end;
constructor TPoint2DOrTPoint3D.create(x, y, z: integer);
begin
select := ePoint3D;
obj := TPoint3D.create(x, y, z);
end;
constructor TPoint2DOrTPoint3D.create(myClass: TPoint2D);
begin
select := ePoint2D;
obj := TPoint2D;
end;
constructor TPoint2DOrTPoint3D.create(myClass: TPoint3D);
begin
select := ePoint3D;
obj := TPoint3D;
end;
destructor TPoint2DOrTPoint3D.Destroy;
begin
if assigned(obj) then
case select of
ePoint2D:
TPoint2D(obj).Free;
ePoint3D:
TPoint3D(obj).Free;
end;
end;
procedure Test;
var
PointList: TObjectList<TPoint2DOrTPoint3D>;
I: integer;
Pt: TPoint2DOrTPoint3D;
P3D: TPoint3D;
P2D: TPoint2D;
begin
PointList := TObjectList<TPoint2DOrTPoint3D>.create;
PointList.OwnsObjects := true;
PointList.Add(TPoint2DOrTPoint3D.create(10, 10));
PointList.Add(TPoint2DOrTPoint3D.create(50, 10));
PointList.Add(TPoint2DOrTPoint3D.create(-10, 10, 90));
PointList.Add(TPoint2DOrTPoint3D.create(3, 50, 70));
for Pt in PointList do
begin
case Pt.select of
ePoint2D:
begin
P2D := Pt.obj;
writeln(P2D.x, ' ', P2D.y);
end;
ePoint3D:
begin
P3D := Pt.obj;
writeln(P3D.x, ' ', P3D.y, ' ', P3D.z);
end;
end;
end;
PointList.Destroy;
end;
begin
try
Test;
except
on E: Exception do
writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
这可能有点矫枉过正,但我认为这可能是相关的
在Delphi XE中编程