2010-11-04 46 views
0

我知道如何做到这一点,但又一次忘记了......非常烦人,因为我正在处理一个包含XML文件列表的类,现在我只想使用for-in循环遍历此列表中的所有文件。这是我现在拥有的班级:
枚举自定义数组,因此我可以使用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类中也需要一个枚举器!
如何创建该枚举器?



您可能想知道为什么我使用这种复杂的结构。好吧,它可能很复杂,但它会被其他一些开发者使用,我不想提供比他们需要更多的方法。这样,我只给他们方法“添加”,“清除”和“计数”循环通过列表,以及TItem本身上定义的任何属性。他们不需要比这更多,但我可能稍后再添加一些功能...

回答

2

找到它了!我需要创建一个新的类,我已经叫TItemEnumerator,我也包括它在TXmlFileList类,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行代码和大量注释。班级结构实际上帮助我从使用它的人的角度简单地看待这一切。那些使用它的人不需要寻找使用的类型和方法。他们的选择是非常有限的...

+1

为什么使TXFAFileList.TItem'专用,如果您稍后暴露它呢? – 2010-11-04 10:56:36

+0

好问题。:-)基本上,我只是遵循了一种模式,并暴露出课程意味着打破模式。此外,如果我喜欢,我总是可以决定让枚举器返回任何其他类型。例如,只是标题。但是接下来我必须将TXmlFile声明为公开。 – 2010-11-04 11:03:43

+1

Primoz有一系列关于您可能会发现有用的统计员的文章:http://www.thedelphigeek.com/search/label/enumerators – 2010-11-05 01:49:30