delphi - 如何为从 TDictionary 派生的类创建自定义枚举器?

标签 delphi enumerator tdictionary

我已经定义了一个从 TDictionary 派生的集合,并且需要定义一个应用附加过滤器的自定义枚举器。

我陷入困境,因为我无法访问 TDictionary FItems 数组(它是私有(private)的),因此我无法定义 MoveNext 方法

您将如何在从 TDictionary 派生的类上重新定义过滤枚举器?

这是一个简单的代码来说明我想要做什么:

TMyItem = class(TObject)
public
  IsHidden:Boolean; // The enumerator should not return hidden items
end;
TMyCollection<T:TMyItem> = class(TDictionary<integer,T>)
public
   function GetEnumerator:TMyEnumerator<T>; // A value filtered enumerator
   type
     TMyEnumerator = class(TEnumerator<T>)
     private
       FDictionary: TMyCollection<integer,T>;
       FIndex: Integer;
       function GetCurrent: T;
     protected
       function DoGetCurrent: T; override;
       function DoMoveNext: Boolean; override;
     public
       constructor Create(ADictionary: TMyCollection<integer,T>);
       property Current: T read GetCurrent;
       function MoveNext: Boolean;
     end;
end;

function TMyCollection<T>.TMyEnumerator.MoveNext: Boolean;
begin
// In below code, FIndex is not accessible, so I can't move forward until my filter applies
  while FIndex < Length(FDictionary.FItems) - 1 do   
  begin
    Inc(FIndex);
    if (FDictionary.FItems[FIndex].HashCode <> 0) 
      and not(FDictionary.FItems[FIndex].IsHidden) then // my filter
      Exit(True);
  end;
  Result := False;
end;

最佳答案

您可以将枚举器基于 TDictionary 的枚举器,因此您实际上不需要访问 FItems。即使您按照 Barry 的建议围绕 TDictionary 编写了一个包装类,这仍然有效。枚举器看起来像这样:

TMyEnumerator = class
protected
  BaseEnumerator: TEnumerator<TPair<Integer, T>>; // using the key and value you used in your sample
public
  function MoveNext:Boolean;
  property Current:T read GetCurrent;
end;

function TMyEnumerator.MoveNext:Boolean;
begin
  Result := BaseEnumerator.MoveNext;
  while Result and (not (YourTestHere)) do // ie: the base enumerator returns everything, reject stuff you don't like
    Result := BaseEnumerator.MoveNext;
end;

function TMyEnumerator.Current: T;
begin
  Result := BaseEnumerator.Current.Value; // Based on your example, it's value you want to extract
end;

这是一个完整的 100 行控制台应用程序,演示了这一点:

program Project23;

{$APPTYPE CONSOLE}

uses
  SysUtils, Generics.Collections;

type

  TMyType = class
  public
    Int: Integer;
    constructor Create(anInteger:Integer);
  end;

  TMyCollection<T:TMyType> = class(TDictionary<integer,T>)
  strict private
    type
      TMyEnumerator = class
      protected
        BaseEnum: TEnumerator<TPair<Integer,T>>;
        function GetCurrent: T;
      public
        constructor Create(aBaseEnum: TEnumerator<TPair<Integer,T>>);
        destructor Destroy;override;

        function MoveNext:Boolean;
        property Current:T read GetCurrent;
      end;
  public
    function GetEnumerator: TMyEnumerator;
  end;

{ TMyCollection<T> }

function TMyCollection<T>.GetEnumerator: TMyEnumerator;
begin
  Result := TMyEnumerator.Create(inherited GetEnumerator);
end;

{ TMyType }

constructor TMyType.Create(anInteger: Integer);
begin
  Int := anInteger;
end;

{ TMyCollection<T>.TMyEnumerator }

constructor TMyCollection<T>.TMyEnumerator.Create(aBaseEnum: TEnumerator<TPair<Integer, T>>);
begin
  BaseEnum := aBaseEnum;
end;

function TMyCollection<T>.TMyEnumerator.GetCurrent: T;
begin
  Result := BaseEnum.Current.Value;
end;

destructor TMyCollection<T>.TMyEnumerator.Destroy;
begin
  BaseEnum.Free;
  inherited;
end;

function TMyCollection<T>.TMyEnumerator.MoveNext:Boolean;
begin
  Result := BaseEnum.MoveNext;
  while Result and ((BaseEnum.Current.Value.Int mod 2) = 1) do
    Result := BaseEnum.MoveNext;
end;

var TMC: TMyCollection<TMyTYpe>;
    V: TMyType;

begin
  try
    TMC := TMyCollection<TMyType>.Create;
    try
      // Fill TMC with some values
      TMC.Add(1, TMyType.Create(1));
      TMC.Add(2, TMyType.Create(2));
      TMC.Add(3, TMyType.Create(3));
      TMC.Add(4, TMyType.Create(4));
      TMC.Add(5, TMyType.Create(5));
      TMC.Add(6, TMyType.Create(6));
      TMC.Add(7, TMyType.Create(7));
      TMC.Add(8, TMyType.Create(8));
      // Filtered-enum
      for V in TMC do
        WriteLn(V.Int);
      ReadLn;
    finally TMC.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

关于delphi - 如何为从 TDictionary 派生的类创建自定义枚举器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6044300/

相关文章:

c# - 二叉搜索树 IEnumerator.MoveNext() 非递归中序遍历实现。如何?

delphi - TDictionary<TVehicle, TPerson> 的 Equals 和 GetHashCode

image - delphi:如何将图像放入DBGrid标题中?

delphi - 用 Delphi 编写请等待屏幕的最简单方法是什么?

android - 如何获取应用程序id(包+模块名)delphi XE5/XE6/XE7

ruby - enum#feed 如何在 ruby​​ 中工作?

haskell - 如何创建不断重试的枚举器

delphi - TDictionary 重复条目(Delphi)

delphi - 按 Integer 键按升序对 TDictionary 进行排序

Delphi读取溢出标志