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

发布于 2024-09-30 10:42:54 字数 1378 浏览 3 评论 0原文

我知道如何做到这一点,但又忘记了...非常烦人,因为我正在开发一个包含 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 本身定义的任何属性。他们不需要更多的功能,尽管我稍后可能会添加更多功能......

I knew how to do this but forgot again... Quite irritating, because I'm working on a class that contains a list of XML files, and now I just want to use a for-in loop to walk through all files in this list. This is the class I have right now:

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;

Looks funny? :-) I know, but I want to hide the definition of the TXmlFile class to the outside world. Basically, the TXmlFileList class allows me to simply refer to XmlFileList[I] to get the file at position I. Works nicely.

But now I want to loop through the TXmlFileList.TItem elements, so I have to expose the TXmlFileList.TItem class. It's not enough, though. It needs an enumerator too in the TXmlFileList class!
How to create that enumerator?

You're probably wondering why I use this complex construction. Well, it might be complex but it will be used by some other developers and I don't want to provide more methods than they need. This way, I only give them the methods "Add", "Clear" and "Count" to loop through the list, and any property defined on the TItem itself. They don't need more than this, although I might add a few more features later on...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

旧伤慢歌 2024-10-07 10:42:54

找到了!我需要创建一个新类,我将其称为 TItemEnumerator,并且我还在 TItem 之后将其包含在 TXmlFileList 类中:

    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 行代码和大量注释。类结构实际上帮助我从使用它的人的角度来看这一切看起来很简单。使用它的人不需要寻找类型和方法来使用。他们的选择非常有限……

Found it! I needed to create a new class, which I've called TItemEnumerator, and I also included it in the TXmlFileList class, right after 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;

Implementation was easy, just an additional method to TXmlFileList:

    function GetEnumerator: TItemEnumerator;

And finally, exposing the class to the outside world, which I did by adding this to TXmlFileList:

type TXmlFile = TXmlFileList.TItem;

Yeah, that dirty! :-)


It results in this code:

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;

And yes, you can start scratching your head when you look at it, but it's a great solution to hide many functions from inexperienced developers! Now they only see what they need to see. (And hopefully they never look at this sourcecode!)
I just expected that I needed to write more code than this...


Why exposing the TItem type with a different name? Actually, these classes are wrapped again in a bigger class TXmlManager that also handles stylesheets, transformations, validations and a bunch of other stuff. TXmlFile is actually exposed at the TXmlManager level, not the TXmlFileList class. TXmlManager contains a few other similar lists where I just re-use the name TItem. There are no conflicts, though, because the parents need to be added to refer to the proper class type.
And while the class header might look complex with nearly 200 lines of code, the rest of the unit is quite slim, with almost 700 lines of code and plenty of comments. The class structure is actually helping me to make it all look simply from the viewpoint of those who use it. Those who use it, don't need to look for types and methods to use. Their choices are just very limited...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文