Search code examples
delphiinterfaceenumerationdelphi-xe6

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?


Solution

  • 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.