How to do it in TObjectList?

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 does not compile:

[dcc32 error] Project1.dpr (15): E2010 Incompatible types: "TObject" and "Pointer"

It seems that the Delphi for in construct does not treat untyped, unpublished TObjectList but as an enumerated target.

How to list objects in a TObjectList ?

What am i doing now

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 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 a counter? Just a reason.

+6
source share
3 answers

How to list objects in a TObjectList ?

To answer a specific question, this is an example of introducing an enumerator. Note that you need to create a TObjectList child to add the GetEnumerator function. You can do without a subclass with the help of a class helper, but I leave this 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 enumerator implementation uses an entry instead of a class. This has the advantage of not allocating an extra object to the heap when executing 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; 

As others have noted, there is a generics class that is better to use, TObjectList<T> .

+4
source

Using generics can have a typed list of objects (I just noticed a comment, but ended up poorly anyway)

And if you are looking for a good reason to use TObjectList<T> , then the reason is that it will save you a lot of types in your code

 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. 
+5
source

The enumerator for TObjectList declared in TList , which is the class from which TObjectList is derived. RTL does not bother to declare a more specific counter for TObjectList . Thus, you are left with the TList enumerator. Which gives elements of type Pointer , which are the type of element stored in TList .

There are probably several reasons why RTL designers decided not to do anything with TObjectList . For example, I suggest the following potential causes:

  • TObjectList , like everything in Contnrs , is deprecated and deprecated by generic containers in Generics.Collections . Why waste resources changing an outdated class.
  • Even if the TObjectList had an enumerator that gave the TObject elements, you still have to distinguish them. Would an enumerator that gave TObject be much more useful?
  • Designers simply forgot that this class existed when adding counters.

What you have to do. The obvious choice is to use TList<T> or TObjectList<T> from Generics.Collections . If you want to continue with TObjectList , you can subclass it and add an enumerator that would give TObject . If you do not know how to do this, you can learn how to do this from the documentation . Or you can use the inherited enumerator and the type thrown by the pointers it gives.

It seems to me that since you are ready to change the code from the indexed for loop to the for for loop, this means that you are ready to make unnecessary changes to the code. In this case, a common container would seem to be the obvious choice.

+3
source

Source: https://habr.com/ru/post/976011/


All Articles