枚举自定义数组,以便我可以使用for-in

时间:2010-11-04 10:10:34

标签: delphi winapi delphi-2007 enumeration

我知道如何做到但又忘记了......非常恼火,因为我正在开发一个包含XML文件列表的类,现在我只想使用for-in循环来遍历所有此列表中的文件。这是我现在的课程:

type
  TXmlFileList = class( TInterfacedObject )
  private
    type
      TItem = class( TInterfacedObject )
      strict private
        FCaption: string;
      protected
        constructor Create( const ACaption: string; const AXML: WideString );
      public
        destructor Destroy; override;
        property Caption: string read FCaption;
      end;
  strict private
    FXmlFiles: array of TXmlFileList.TItem;
  strict protected
    function GetXmlFile( index: Integer ): TXmlFileList.TItem;
  public
    constructor Create( );
    destructor Destroy; override;
    function Add( const ACaption: string; const AXML: WideString ): Integer; overload;
    function Add( const AFilename: string ): Integer; overload;
    function Count: Integer;
    procedure Clear;
    property XmlFile[ index: Integer ]: TXmlFileList.TItem read GetXmlFile; default;
  end;

看起来好笑吗? :-)我知道,但我想隐藏TXmlFile类的定义到外面的世界。基本上,TXmlFileList类允许我简单地引用XmlFileList [I]来获取位置I的文件。很好地工作。

但是现在我想循环遍历TXmlFileList.TItem元素,所以我必须公开TXmlFileList.TItem类。但这还不够。它在TXmlFileList类中也需要一个枚举器!
如何创建该枚举器?
您可能想知道为什么我使用这种复杂的结构。好吧,它可能很复杂但是它会被其他一些开发人员使用,我不想提供比他们需要的更多的方法。这样,我只给他们方法“Add”,“Clear”和“Count”循环遍历列表,以及TItem本身定义的任何属性。他们不需要更多,但我可能会在稍后添加更多功能......

1 个答案:

答案 0 :(得分:2)

发现它!我需要创建一个新类,我称之为TItemEnumerator,我也将它包含在TXtemFileList类中,就在TItem之后:

    type
      TItemEnumerator = class( TObject )
      strict private
        FOwner: TXmlFileList;
        FIndex: Integer;
      protected
        constructor Create(AOwner: TXmlFileList);
      public
        function GetCurrent: TItem;
        function MoveNext: Boolean;
        property Current: TItem read GetCurrent;
      end;

实现很简单,只是TXmlFileList的另一种方法:

    function GetEnumerator: TItemEnumerator;

最后,将该类暴露给外部世界,我将其添加到TXmlFileList:

type TXmlFile = TXmlFileList.TItem;
是的,那脏! :-)


导致此代码:

type
  TXmlFileList = class( TInterfacedObject )
  private
    type
      TItem = class( TInterfacedObject )
      strict private
        FCaption: string;
      protected
        constructor Create( const ACaption: string; const AXML: WideString );
      public
        destructor Destroy; override;
        property Caption: string read FCaption;
      end;
    type
      TItemEnumerator = class( TObject )
      strict private
        FOwner: TXmlFileList;
        FIndex: Integer;
      protected
        constructor Create(AOwner: TXmlFileList);
      public
        function GetCurrent: TItem;
        function MoveNext: Boolean;
        property Current: TItem read GetCurrent;
      end;
  strict private
    FXmlFiles: array of TXmlFileList.TItem;
  strict protected
    function GetXmlFile( index: Integer ): TXmlFileList.TItem;
  public
    type TXmlFile = TXmlFileList.TItem;
    constructor Create( );
    destructor Destroy; override;
    function Add( const ACaption: string; const AXML: WideString ): Integer; overload;
    function Add( const AFilename: string ): Integer; overload;
    function Count: Integer;
    function GetEnumerator: TItemEnumerator;
    procedure Clear;
    property XmlFile[ index: Integer ]: TXmlFileList.TItem read GetXmlFile; default;
  end;

是的,当你看到它时,你可以开始摸不着头脑,但这是一个很好的解决方案,可以隐藏无经验的开发人员的许多功能!现在他们只看到他们需要看到的东西。 (希望他们永远不会看到这个源代码!)我只是期望我需要写更多的代码而不是......


为什么要使用不同的名称公开TItem类型?实际上,这些类再次包装在一个更大的类TXmlManager中,该类还处理样式表,转换,验证和一堆其他东西。 TXmlFile实际上是在TXmlManager级别公开的,而不是TXmlFileList类。 TXmlManager包含一些其他类似的列表,我只是重新使用名称TItem。但是,没有冲突,因为需要添加父级来引用正确的类类型。
虽然类标题可能看起来很复杂,有近200行代码,但单元的其余部分相当纤薄,有近700行代码和大量注释。类结构实际上帮助我从使用它的人的角度简单地看待它。使用它的人不需要寻找使用的类型和方法。他们的选择非常有限......