实现列表枚举器OfType< T>在德尔福 [英] Implementing List Enumerator OfType<T> in Delphi

查看:189
本文介绍了实现列表枚举器OfType< T>在德尔福的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Delphi XE实现枚举器,允许按类型过滤列表的元素。我已经快速组装了一个测试单元,如下所示:

I am using Delphi XE to implement an enumerator that allows filtering the elements of the list by type. I have quickly assembled a test unit as follows:

unit uTestList;

interface

uses Generics.Collections;

type
  TListItemBase = class(TObject)
  end; { TListItemBase }

  TListItemChild1 = class(TListItemBase)
  end;

  TListItemChild2 = class(TListItemBase)
  end;

  TTestList<T : TListItemBase> = class;

  TOfTypeEnumerator<T, TFilter> = class(TInterfacedObject, IEnumerator<TFilter>)
  private
    FTestList : TList<T>;
    FIndex : Integer;
  protected
    constructor Create(Owner : TList<T>); overload;

    function GetCurrent : TFilter;
    function MoveNext : Boolean;
    procedure Reset;

    function IEnumerator<TFilter>.GetCurrent = GetCurrent;
    function IEnumerator<TFilter>.MoveNext = MoveNext;
    procedure IEnumerator<TFilter>.Reset = Reset;
  end;

  TOfTypeEnumeratorFactory<T, TFilter> = class(TInterfacedObject, IEnumerable)
  private
    FTestList : TList<T>;
  public
    constructor Create(Owner : TList<T>); overload;
    function GetEnumerator : TOfTypeEnumerator<T, TFilter>;
  end;

  TTestList<T : TListItemBase> = class(TList<T>)
  public
    function OfType<TFilter : TListItemBase>() : IEnumerable;
  end; { TTestList }


implementation

{ TOfTypeEnumerator<T, TFilter> }

constructor TOfTypeEnumerator<T, TFilter>.Create(Owner: TList<T>);
begin
  inherited;
  FTestList := Owner;
  FIndex := -1;
end;

function TOfTypeEnumerator<T, TFilter>.GetCurrent: TFilter;
begin
  Result := TFilter(FTestList[FIndex]);
end;

function TOfTypeEnumerator<T, TFilter>.MoveNext: Boolean;
begin
  Inc(FIndex);
  while ((FIndex < FTestList.Count)
         and (not FTestList[FIndex].InheritsFrom(TFilter))) do
  begin
    Inc(FIndex);
  end; { while }
end;

{ TOfTypeEnumeratorFactory<T, TFilter> }

constructor TOfTypeEnumeratorFactory<T, TFilter>.Create(Owner: TList<T>);
begin
  inherited;
  FTestList := Owner;
end;

function TOfTypeEnumeratorFactory<T, TFilter>.GetEnumerator: TOfTypeEnumerator<T, TFilter>;
begin
  Result := TOfTypeEnumerator<T,TFilter>.Create(FTestList);
end;

{ TTestList<T> }

function TTestList<T>.OfType<TFilter>: IEnumerable;
begin
  Result := TOfTypeEnumeratorFactory<T,TFilter>.Create(self);
end;

end.

编译本机失败,可怕的F2084内部错误:D7837。我当然可以做到这一点没有一个枚举者,但我宁愿有一个可以使代码一致。我试图在Spring4D之上实现一个类似的编译器问题,但是我想在这里提出一个简单的vanilla Delphi问题。

Compiling this unit fails with the dreaded F2084 Internal Error: D7837. I can certainly do this without an enumerator, but I'd rather have one available to make the code consistent. I had a similar compiler problem when trying to implement this on top of Spring4D, but figured I would put out a plain, vanilla Delphi issue here.

有没有人有替代实际编译?

Does anyone have an alternate implementation that actually compiles?

谢谢。

推荐答案

你不想使用IEnumerator< T>从System.pas,相信我。那个东西带来了很多麻烦,因为它继承自IEnumerator,所以GetCurrent方法具有不同的结果(TObject for IEnumerator和T为IEnumerator< T>)。

You don't want to use the IEnumerator<T> from System.pas, trust me. That thing brings along so much trouble because it inherits from IEnumerator and so has that GetCurrent method with different results (TObject for IEnumerator and T for IEnumerator<T>).

更好定义您自己的IEnumerator< T>:

Better define your own IEnumerator<T>:

IEnumerator<T> = interface
  function GetCurrent: T;
  function MoveNext: Boolean;
  procedure Reset;
  property Current: T read GetCurrent;
end;

与IEnumerable相同。我会说定义你自己的IEnumerable< T>:

Same with IEnumerable. I would say define your own IEnumerable<T>:

IEnumerable<T> = interface
  function GetEnumerator: IEnumerator<T>;
end;

如果您在TOFTypeEnumerator< T,TFilter>您可以删除导致ICE的方法解析条款。

If you use that in your TOfTypeEnumerator<T, TFilter> you can remove the method resolution clauses causing the ICE.

当您这样做时,您将看到其他编译器错误E2008,E2089等等。

When you do that you will start seeing other compiler errors E2008, E2089 and some more.


  • 调用刚才在构造函数中继承,尝试在不存在的祖先类中调用具有相同签名的构造函数。所以更改它继承创建。

  • calling just inherited in your constructor tries to call the constructor with the same signature in your ancestor class which does not exist. So change it to inherited Create.

不要使用IEnumerable,但使用IEnumerable< TFilter>因为这是你想要枚举的

don't use IEnumerable but use IEnumerable<TFilter> because that is what your want to enumerator over

不要使用只允许对象使用的方法和转换,或者在T和TFilter

don't use methods and casts that are only allowed for objects or specify the class constraint on T and TFilter

MoveNext需要一个结果

MoveNext needs a Result

编译单元。做了一个快速的测试,它似乎工作:

Here is the compiling unit. Did a quick test and it seems to work:

unit uTestList;

interface

uses
  Generics.Collections;

type
  IEnumerator<T> = interface
    function GetCurrent: T;
    function MoveNext: Boolean;
    property Current: T read GetCurrent;
  end;

  IEnumerable<T> = interface
    function GetEnumerator: IEnumerator<T>;
  end;

  TOfTypeEnumerator<T: class; TFilter: class> = class(TInterfacedObject, IEnumerator<TFilter>)
  private
    FTestList: TList<T>;
    FIndex: Integer;
  protected
    constructor Create(Owner: TList<T>); overload;

    function GetCurrent: TFilter;
    function MoveNext: Boolean;
  end;

  TOfTypeEnumeratorFactory<T: class; TFilter: class> = class(TInterfacedObject, IEnumerable<TFilter>)
  private
    FTestList: TList<T>;
  public
    constructor Create(Owner: TList<T>); overload;
    function GetEnumerator: IEnumerator<TFilter>;
  end;

  TTestList<T: class> = class(TList<T>)
  public
    function OfType<TFilter: class>: IEnumerable<TFilter>;
  end;

implementation

{ TOfTypeEnumerator<T, TFilter> }

constructor TOfTypeEnumerator<T, TFilter>.Create(Owner: TList<T>);
begin
  inherited Create;
  FTestList := Owner;
  FIndex := -1;
end;

function TOfTypeEnumerator<T, TFilter>.GetCurrent: TFilter;
begin
  Result := TFilter(TObject(FTestList[FIndex]));
end;

function TOfTypeEnumerator<T, TFilter>.MoveNext: Boolean;
begin
  repeat
    Inc(FIndex);
  until (FIndex >= FTestList.Count) or FTestList[FIndex].InheritsFrom(TFilter);
  Result := FIndex < FTestList.Count;
end;

{ TOfTypeEnumeratorFactory<T, TFilter> }

constructor TOfTypeEnumeratorFactory<T, TFilter>.Create(Owner: TList<T>);
begin
  inherited Create;
  FTestList := Owner;
end;

function TOfTypeEnumeratorFactory<T, TFilter>.GetEnumerator: IEnumerator<TFilter>;
begin
  Result := TOfTypeEnumerator<T, TFilter>.Create(FTestList);
end;

{ TTestList<T> }

function TTestList<T>.OfType<TFilter>: IEnumerable<TFilter>;
begin
  Result := TOfTypeEnumeratorFactory<T,TFilter>.Create(self);
end;

end.

这篇关于实现列表枚举器OfType&lt; T&gt;在德尔福的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆