0

I have created a TMyList-class that inherited from the Delphi TObjectList<T>. After changing it to a TObjectList<T> from Spring4D, I have an issue using the enumerator.

I we use the enumerator somewhere in the code, the object will be destroyed as soon as the enumerator is destroyed (eg. after for ... in ...). This is due to the reference counting used inside the enumerator, but from the outside it is used as an object in the code and I expect it not to be auto destroyed.

This looks like a bug in Spring4D, or maybe it is simply not possible to use Spring4D lists with object references?

A simple example to reproduct is below:

unit Unit188;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Spring.Collections.Lists, Vcl.StdCtrls;

type
  TForm188 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TMyList = class(TObjectList<TObject>)
    procedure DoSomething;
    destructor Destroy; override;
  end;

var
  Form188: TForm188;

implementation

{$R *.dfm}

{ TMyList }

destructor TMyList.Destroy;
begin
  ShowMessage('Destructor called');
  inherited;
end;

procedure TMyList.DoSomething;
var
  o: TObject;
begin
  for o in Self do;  // <=== here the TMyList is destroyed as soon as the enumerator is destroyed
end;

procedure TForm188.Button1Click(Sender: TObject);
var
  l: TMyList;
begin
  l := TMyList.Create;
  l.DoSomething;
end;

end.
Laurens
  • 325
  • 2
  • 12
  • 1
    Spring4D collections are reference counted, you need to use interface reference to store such list. Instead of `l: TMyList` you need `l: IList`. You will probably want to declare your custom interface to expose DoSomething method or you need to do typecasting to call it. – Dalija Prasnikar Aug 11 '21 at 09:57
  • I know they can be reference counted, but that does not mean that the enumerator should be ref.counted as well. I think that is the underlying issue. – Laurens Aug 11 '21 at 11:32
  • 1
    It is not they can be reference counted, they **are** reference counted. Any code that triggers reference counting will destroy reference counted object that does not have at least one strong reference - object references are not strong references, only interface references are. When you call `for o in Self do` enumerator code triggers reference counting on collection (Self) and after enumeration is completed reference count will be decreased and your collection gone. – Dalija Prasnikar Aug 11 '21 at 13:17
  • 2
    The enumerator holds a reference to its list via the reference counting mechanism so it still will work if the actual list reference would be dropped because then the enumerator will keep the list alive. This is used when chaining methods like `Where` that return yet another `IEnumerable`. Spring collections have to be used as interfaces, period. – Stefan Glienke Aug 11 '21 at 22:52
  • Thanks both, it is clear to me! – Laurens Aug 12 '21 at 11:37

0 Answers0