I am trying to use for in
to iterate a 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.
And it fails to compile:
[dcc32 Error] Project1.dpr(15): E2010 Incompatible types: 'TObject' and 'Pointer'
It seems as though Delphi's for in
construct does not handle the untyped, undescended, TObjectList
an as enumerable target.
How do i enumerate the objects in a TObjectList
?
My current code is:
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;
For no good reason, i was hoping to change it to:
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;
Why use an enumerator? Just cause.
How do i enumerate the objects in a TObjectList?
To answer the specific question, this is an example of introducing an enumerator.
Note that you will have to create a descendant of TObjectList
in order to add the GetEnumerator
function. You could do without subclassing with a class helper, but I leave that as an exercise for the interested reader.
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;
This implementation of an enumerator uses a record instead of a class. This has the advantage of not allocating an extra object on the heap when doing for..in
enumerations.
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;
As others have noted, there is a generics class that is a better option to use, TObjectList<T>
.