实现列表枚举器OfType< T>在德尔福 [英] Implementing List Enumerator OfType<T> in Delphi
问题描述
我使用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< T>在德尔福的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!