我使用Delphi XE实现枚举器,允许按类型过滤列表的元素。我已经快速组装了一个测试单元如下:
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,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问题。
有没有人有实际编译的替代实现?
谢谢。
解决方法
您不想使用IEnumerator< T>从System.pas,相信我。那个东西带来了很多麻烦,因为它继承自IEnumerator,因此具有不同结果的GetCurrent方法(用于IEnumerator的TObject和用于IEnumerator&T的T)。
更好地定义您自己的IEnumerator< T:
IEnumerator<T> = interface function GetCurrent: T; function MoveNext: Boolean; procedure Reset; property Current: T read GetCurrent; end;
与IEnumerable相同。我会说定义你自己的IEnumerable< T:
IEnumerable<T> = interface function GetEnumerator: IEnumerator<T>; end;
如果您在TOFTypeEnumerator< T,TFilter>您可以删除导致ICE的方法解析条款。
当您这样做时,您将看到其他编译器错误E2008,E2089等。
>在你的构造函数中继承的调用尝试在你的祖先类中调用不存在相同签名的构造函数。所以改为继承创建。
>不要使用IEnumerable,但使用IEnumerable< TFilter>因为这是你想要的枚举者
>不要使用仅允许对象使用的方法和转换,或者在T和TFilter上指定类约束
> MoveNext需要一个结果
这是编译单元。做了一个快速测试,似乎工作:
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>.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>.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.