如何正确地使接口支持迭代?

War*_* P 5 delphi generics interface list

我如何从接口公开这个TList,IEnumerator或者IEnumerator<IFungibleTroll>?我正在使用Delphi XE.

这是我有多远:

unit FungibleTrollUnit;

interface

uses
  Windows, Messages, SysUtils,
  Variants, Classes, Graphics,
  Controls, Forms,
  Generics.Collections;

type
  IFungibleTroll = interface
    ['{03536137-E3F7-4F9B-B1F5-2C8010A4D019}']
       function GetTrollName:String;
       function GetTrollRetailPrice:Double;
  end;


  TFungibleTrolls = class (TInterfacedObject,IEnumerable<IFungibleTroll>)
      protected
         FTrolls:TList<IFungibleTroll>;

      public
          // IEnumerable
          function GetEnumerator:IEnumerator<IFungibleTroll>;//
//          function GetEnumerator:IEnumerator; overload;

         // find/search app feature requires searching.
         // this

         function FindSingleItemByName(aName:String;patternMatch:Boolean):IFungibleTroll;
         function FindMultipleItemsByName(aName:String;patternMatch:Boolean):IEnumerable<IFungibleTroll>;
         function FindSingleItemByIdentifier(anIdentifer:String):IFungibleTroll;// use internal non-visible identifier to find an app.

         constructor Create;

         property Trolls:TList<IFungibleTroll> read FTrolls; // implements IEnumerable<IFungibleTroll>;??
  private
  end;




implementation


{ TFungibleTrolls }

constructor TFungibleTrolls.Create;
begin
         FTrolls := TList<IFungibleTroll>.Create;

end;

function TFungibleTrolls.FindMultipleItemsByName(aName: String;
  patternMatch: Boolean): IEnumerable<IFungibleTroll>;
begin

end;

function TFungibleTrolls.FindSingleItemByIdentifier(
  anIdentifer: String): IFungibleTroll;
begin

end;

function TFungibleTrolls.FindSingleItemByName(aName: String;
  patternMatch: Boolean): IFungibleTroll;
begin

end;



function TFungibleTrolls.GetEnumerator: IEnumerator<IFungibleTroll>;
begin
  result := FTrolls.GetEnumerator;
end;

//function TFungibleTrolls.GetEnumerator: IEnumerator;
//begin
//  result := FTrolls.GetEnumerator; // type IEnumerator<IFungibleTroll> or IEnumerator?
//end;


end.
Run Code Online (Sandbox Code Playgroud)

我陷入三个错误中的一个,我无法弄清楚如何解决:

[DCC Error] FungibleTrollUnit.pas(26): E2252 Method 'GetEnumerator' with identical parameters already exists -要么-

[DCC Error] FungibleTrollUnit.pas(19): E2291 Missing implementation of interface method IEnumerable.GetEnumerator -要么- [DCC Error] FungibleTrollUnit.pas(19): E2291 Missing implementation of interface method IEnumerable.GetEnumerator

似乎我必须声明两种形式的GetEnumerator,如果我声明TFungibleTrolls来实现IEnumerable,但我似乎无法弄清楚如何使用重载,或者没有重载,或使用"方法解析子句",如这个:

      function IEnumerable.GetEnumerator = GetPlainEnumerator; // method resolution clause needed?
      function GetEnumerator:IEnumerator<IFungibleTroll>;
      function GetPlainEnumerator:IEnumerator;
Run Code Online (Sandbox Code Playgroud)

这可能看起来像IEnumerable的一个非常基本的用途,并使接口支持迭代,然而,我被卡住了.

更新:似乎当我尝试在没有首先声明的情况下执行此操作时List<T>,我陷入了由IEnumerable<T>继承的事实引起的裂缝IEnumerable,然而,我的类必须提供多个,而不是单个get枚举器方法,因为我的class不是通用的,除非我使用泛型List<T>声明,否则它不能直接"映射"到IEnumerable的要求.Marjan的示例在编译成项目(.dproj + .dpr)时有效,但在内置到包(.dproj + .dpk)并在IDE中编译时则不然.它可以在命令行中,在包中运行,但不能在IDE中,在包中运行.

Mar*_*ema 5

不是直接回答你的问题(仍在继续),但这是我为了获得"接口枚举器"而做的,即支持迭代的接口类:

IList<T> = interface(IInterface)
  [...]
  function GetEnumerator: TList<T>.TEnumerator;
  function Add(const Value: T): Integer;
end;

type
  TBjmInterfacedList<T> = class(TBjmInterfacedObject, IList<T>)
  strict private
    FList: TList<T>;
    function GetEnumerator: TList<T>.TEnumerator;
  strict protected
    function Add(const Value: T): Integer;
  public
    constructor Create; override;
    destructor Destroy; override;
  end;

implementation

constructor TBjmInterfacedList<T>.Create;
begin
  inherited;
  FList := TList<T>.Create;
end;

destructor TBjmInterfacedList<T>.Destroy;
begin
  FreeAndNil(FList);
  inherited;
end;

function TBjmInterfacedList<T>.GetEnumerator: TList<T>.TEnumerator;
begin
  Result := FList.GetEnumerator;
end;

function TBjmInterfacedList<T>.Add(const Value: T): Integer;
begin
  Result := FList.Add(Value);
end;
Run Code Online (Sandbox Code Playgroud)

然后你可以做以下事情:

ISite = interface(IInterface)
  ...
end;
ISites = interface(IList<ISite>);
  ...
end;

var
  for Site in Sites do begin
    ...
  end;
Run Code Online (Sandbox Code Playgroud)

实现类,如:

TSite = class(TBjmInterfacedObject, ISite)
  ...
end;
TSites = class(TBjmInterfacedList<ISite>, ISites)
  ...
end;
Run Code Online (Sandbox Code Playgroud)

更新

上传到http://www.bjmsoftware.com/delphistuff/stackoverflow/interfacedlist.zip的示例项目源