我正在尝试使用for in
来迭代TObjectList
:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, Contnrs;
var
list: TObjectlist;
o: TObject;
begin
list := TObjectList.Create;
for o in list do
begin
//nothing
end;
end.
无法编译:
[dcc32错误] Project1.dpr(15):E2010不兼容的类型:'TObject'和'Pointer'
似乎Delphi的for in
构造不能处理无类型的,未说明的,TObjectList
和可枚举的目标。
如何枚举TObjectList
中的对象?
我目前的代码是:
procedure TfrmCustomerLocator.OnBatchDataAvailable(BatchList: TObjectList);
var
i: Integer;
o: TObject;
begin
for i := 0 to BatchList.Count-1 do
begin
o := BatchList.Items[i];
//...snip...where we do something with (o as TCustomer)
end;
end;
没有充分的理由,我希望将其改为:
procedure TfrmCustomerLocator.OnBatchDataAvailable(BatchList: TObjectList);
var
o: TObject;
begin
for o in BatchList do
begin
//...snip...where we do something with (o as TCustomer)
end;
end;
为什么要使用枚举器?只是因为。
答案 0 :(得分:5)
使用泛型你可以有一个打字的对象列表(只是注意到了评论,但无论如何都不好完成)
如果您正在寻找使用TObjectList<T>
的充分理由,原因在于它可以为您节省大量代码
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, Generics.Collections;
Type
TCustomer = class
private
public
//Properties and stuff
end;
var
list: TObjectlist<TCustomer>;
c: TCustomer;
begin
list := TObjectList<TCustomer>.Create;
for c in list do
begin
//nothing
end;
end.
答案 1 :(得分:4)
如何枚举 TObjectList ?
中的对象
要回答具体问题,这是引入枚举器的一个示例。
请注意,您必须创建TObjectList
的后代才能添加GetEnumerator
函数。您可以不使用类助手进行子类化,但我将其留作感兴趣的读者的练习。
type
TObjectListEnumerator = record
private
FIndex: Integer;
FList: TObjectList;
public
constructor Create(AList: TObjectList);
function GetCurrent: TObject;
function MoveNext: Boolean;
property Current: TObject read GetCurrent;
end;
constructor TObjectListEnumerator.Create(AList: TObjectList);
begin
FIndex := -1;
FList := AList;
end;
function TObjectListEnumerator.GetCurrent;
begin
Result := FList[FIndex];
end;
function TObjectListEnumerator.MoveNext: Boolean;
begin
Result := FIndex < FList.Count - 1;
if Result then
Inc(FIndex);
end;
//-- Your new subclassed TObjectList
Type
TMyObjectList = class(TObjectList)
public
function GetEnumerator: TObjectListEnumerator;
end;
function TMyObjectList.GetEnumerator: TObjectListEnumerator;
begin
Result := TObjectListEnumerator.Create(Self);
end;
枚举器的这种实现使用记录而不是类。这样做的好处是在执行for..in
枚举时不会在堆上分配额外的对象。
procedure TfrmCustomerLocator.OnBatchDataAvailable(BatchList: TObjectList);
var
o: TObject;
begin
for o in TMyObjectList(BatchList) do // A simple cast is enough in this example
begin
//...snip...where we do something with (o as TCustomer)
end;
end;
正如其他人所说,有一个泛型类是更好的选择,TObjectList<T>
。
答案 2 :(得分:3)
TObjectList
的枚举器在TList
中声明,TObjectList
是派生TObjectList
的类。 RTL不打算为TList
声明更具体的枚举器。所以你留下了Pointer
枚举器。这会产生TList
类型的项目,这是TObjectList
所持有的项目类型。
RTL设计师选择不对TObjectList
做任何事情可能有几个原因。例如,我提出以下潜在原因:
Contnrs
,与Generics.Collections
中的所有内容一样,已被TObjectList
中的通用容器弃用并过时。为什么要花资源修改过时的类。TObject
有一个枚举器产生TObject
个项目,您仍然需要投射它们。屈服TList<T>
的普查员真的会更有帮助吗?你应该怎么做。一个明显的选择是使用TObjectList<T>
中的Generics.Collections
或TObjectList
。如果您希望保留TObject
,则可以对其进行子类化并添加一个产生{{1}}的枚举数。如果您不知道如何操作,可以从documentation了解如何执行此操作。或者你可以使用继承的枚举器并输入它所产生的指针。
在我看来,因为您准备将索引从索引for循环修改为for循环,这意味着您已准备好对代码进行非平凡的更改。在这种情况下,通用容器似乎是显而易见的选择。