Florian Koch
Florian Koch

Reputation: 1502

for ... in with interface

I'm trying to go through a list of objects, but I just want to provide the interface implemented by my objects.

I have 2 cases: Just enumerating trough my list internally (which isn't that big of a problem, i could just use the object instead of the interface), and a property.

ITemplate = interface
  ...
end;

TTemplate = class (TInterfacedObject, ITemplate)
  ...
end;

TMyClass = class
strict private
  FTemplates: TObjectList<TTemplate>;
  function GetTemplates: IEnumerable<ITemplate>;
  ...
public
  property Templates: IEnumerable<ITemplate> read GetTemplates;

...

procedure TMyClass.LoopTroughInternally;
var
  template: ITemplate;
begin
  for template in FTemplates do  // isn't working, of course
    foobar(template);
end;

function TMyClass.GetTemplates: IEnumerable<ITemplate>;
begin
  // dunno what to do here...
end;

Is there a way to provide this enumerator without implementing a specific IEnumerable?

Upvotes: 1

Views: 149

Answers (1)

David Heffernan
David Heffernan

Reputation: 612993

Taken at face value, you can just change the local variable template to be of type TTemplate and then you are done. If this code is internal then there's no real need to do anything else.

However, you seem to me to have bigger problems.

type
  TTemplate = class(TInterfacedObject, ITemplate)
    ...
  end;

....

FTemplates: TObjectList<TTemplate>;

This is a big mistake. When you inherit from TInterfacedObject you are saying that the lifetime is managed by interface reference counting. That means that you must stop taking non-reference counted references. Because they are liable to become stale. And you are taking non-reference counted references when you use a TTemplate reference. You compound matters by using TObjectList<T> which is all about lifetime management.

The simple way to escape this is to use a list of interfaces rather than that TObjectList<T>.

FTemplates: TList<ITemplate>;

Now at this point you are done and dusted because you can indeed write

for template in FTemplates do

where template is ITemplate.

Upvotes: 7

Related Questions