好吧,这可能会令人困惑。我要做的是使用枚举器只返回基于类类型的泛型列表中的某些项。
给出以下层次结构:
type
TShapeClass = class of TShape;
TShape = class(TObject)
private
FId: Integer;
public
function ToString: string; override;
property Id: Integer read FId write FId;
end;
TCircle = class(TShape)
private
FDiameter: Integer;
public
property Diameter: Integer read FDiameter write FDiameter;
end;
TSquare = class(TShape)
private
FSideLength: Integer;
public
property SideLength: Integer read FSideLength write FSideLength;
end;
TShapeList = class(TObjectList<TShape>)
end;
如何扩展TShapeList
以便我可以执行类似以下操作:
procedure Foo;
var
ShapeList: TShapeList;
Shape: TShape;
Circle: TCircle;
Square: TSquare;
begin
// Create ShapeList and fill with TCircles and TSquares
for Circle in ShapeList<TCircle> do begin
// do something with each TCircle in ShapeList
end;
for Square in ShapeList<TSquare> do begin
// do something with each TSquare in ShapeList
end;
for Shape in ShapeList<TShape> do begin
// do something with every object in TShapeList
end;
end;
我尝试使用适用版本的Primoz Gabrijelcic在Parameterized Enumerators使用出厂记录扩展TShapeList
,如下所示:
type
TShapeList = class(TObjectList<TShape>)
public
type
TShapeFilterEnumerator<T: TShape> = record
private
FShapeList: TShapeList;
FClass: TShapeClass;
FIndex: Integer;
function GetCurrent: T;
public
constructor Create(ShapeList: TShapeList);
function MoveNext: Boolean;
property Current: T read GetCurrent;
end;
TShapeFilterFactory<T: TShape> = record
private
FShapeList: TShapeList;
public
constructor Create(ShapeList: TShapeList);
function GetEnumerator: TShapeFilterEnumerator<T>;
end;
function FilteredEnumerator<T: TShape>: TShapeFilterFactory<T>;
end;
然后我将Foo
修改为:
procedure Foo;
var
ShapeList: TShapeList;
Shape: TShape;
Circle: TCircle;
Square: TSquare;
begin
// Create ShapeList and fill with TCircles and TSquares
for Circle in ShapeList.FilteredEnumerator<TCircle> do begin
// do something with each TCircle in ShapeList
end;
for Square in ShapeList.FilteredEnumerator<TSquare> do begin
// do something with each TSquare in ShapeList
end;
for Shape in ShapeList.FilteredEnumerator<TShape> do begin
// do something with every object in TShapeList
end;
end;
然而,当我尝试编译关于Foo
的{{1}}时,Delphi 2010会抛出错误。如果我注释掉Incompatible types: TCircle and TShape
循环,那么我会收到有关TCircle
的类似错误。如果我也评论TSquare
循环,则代码编译并运行。嗯,它的工作原理是它枚举了每个对象,因为它们都来自TSquare
。奇怪的是,编译器指示的行号超出了文件末尾的2行。在我的演示项目中,它表示第177行,但只有175行。
有没有办法让这项工作?我希望能够直接分配给Circle而无需经过任何类型转换或检查我的TShape
循环本身。
答案 0 :(得分:3)
您不会在此处显示,但问题可能在于 GetCurrent 的实现。
虽然编译器接受类似
的内容result := FShapeList[FIndex];
在泛型类中,当结果类不等于 TShape 时,这将失败, TCircle 和 TSquare 就是这种情况。这就是它在第三个循环中工作的原因。
将代码更改为
result := T(FShapeList[FIndex]);
你没事。
该错误的不存在的行号是由于解析了编译器完成的内部通用,它不能很好地映射到行号。
答案 1 :(得分:0)
您不能直接在枚举器中执行此操作。我担心你会被“坚持”所困扰。唯一的方法是创建一些辅助枚举器。在你的情况下,尝试注释掉行,直到找到唯一使编译器不满意的行。
很抱歉,这是我所能提出的全部内容。
答案 2 :(得分:0)
你在问题中写了答案:)
你只需要调用正确的函数:
for Circle in ShapeList.FilteredEnumerator<TCircle> do
//blah blah
for Square in ShapeList.FilteredEnumerator<TSquare> do
//blah blah
关于您的代码的一个小注意事项:您可以转储TShapeFilterFactory
记录,只需添加方法:
TShapeFilterEnumerator<T>.GetEnumerator : TShapeFilterEnumerator<T>;
begin
Result := Self;
end;