在 Delphi 中实现 List Enumerator OfType<T>
Posted
技术标签:
【中文标题】在 Delphi 中实现 List Enumerator OfType<T>【英文标题】:Implementing List Enumerator OfType<T> in Delphi 【发布时间】:2012-05-26 07:32:10 【问题描述】:我正在使用 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, 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 之上实现它时,我遇到了类似的编译器问题,但我想我会在这里提出一个普通的、普通的 Delphi 问题。
有没有人有实际编译的替代实现?
谢谢。
【问题讨论】:
在 XE2 中相同。提交给 QC。泛型仍然几乎无法使用。 刚刚提交给 QC -- #105719。谢谢。 qc.embarcadero.com/wc/qcmain.aspx?d=105719 在您的质量控制报告中检查 USc 制造的 cmets。 【参考方案1】:您不想使用 System.pas 中的 IEnumerator
最好定义自己的 IEnumerator
IEnumerator<T> = interface
function GetCurrent: T;
function MoveNext: Boolean;
procedure Reset;
property Current: T read GetCurrent;
end;
与 IEnumerable 相同。我会说定义你自己的 IEnumerable
IEnumerable<T> = interface
function GetEnumerator: IEnumerator<T>;
end;
如果您在 TOfTypeEnumerator
当您这样做时,您将开始看到其他编译器错误 E2008、E2089 等等。
在您的构造函数中调用刚刚继承的函数会尝试调用具有相同签名的构造函数,该签名在您的祖先类中不存在。所以把它改成继承的Create。
不要使用 IEnumerable,而是使用 IEnumerable
不要使用只允许用于对象的方法和强制转换,或者在 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>
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.
【讨论】:
说得好。不幸的是,我遇到您的建议为时已晚;系统单元中的接口实现起来真的很痛苦! 嘿,我看到了你关于 Lambda 和 delphi 的博客文章。我试着看看如何联系你。我似乎无法登录或注册entwickler-ecke.de/viewtopic.php?t=103194&view=df 以获取文件。你有副本吗??【参考方案2】:使用system.IEnumerable<T>
和system.IEnumerator<T>
的工作版本
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 : class; TFilter : class> = class(TInterfacedObject, IEnumerator<TFilter>, IEnumerator)
private
FTestList : TList<T>;
FIndex : Integer;
protected
constructor Create(Owner : TList<T>); overload;
function GetCurrent: TObject;
function GenericGetCurrent : TFilter;
function MoveNext : Boolean;
procedure Reset;
function IEnumerator<TFilter>.GetCurrent = GenericGetCurrent;
end;
TOfTypeEnumeratorFactory<T : class; TFilter : class> = class(TInterfacedObject, IEnumerable<TFilter>, IEnumerable)
private
FTestList : TList<T>;
public
constructor Create(Owner : TList<T>); overload;
function GetEnumerator : IEnumerator;
function GenericGetEnumerator : IEnumerator<TFilter>;
function IEnumerable<TFilter>.GetEnumerator = GenericGetEnumerator;
end;
TTestList<T : TListItemBase> = class(TList<T>)
public
function OfType<TFilter : TListItemBase>() : IEnumerable<TFilter>;
end; TTestList
implementation
TOfTypeEnumerator<T, TFilter>
constructor TOfTypeEnumerator<T, TFilter>.Create(Owner: TList<T>);
begin
inherited Create;
FTestList := Owner;
FIndex := -1;
end;
function TOfTypeEnumerator<T, TFilter>.GenericGetCurrent: TFilter;
begin
Result := TFilter(TObject(FTestList[FIndex]));
end;
function TOfTypeEnumerator<T, TFilter>.GetCurrent: TObject;
begin
Result := 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;
procedure TOfTypeEnumerator<T, TFilter>.Reset;
begin
FIndex := -1;
end;
TOfTypeEnumeratorFactory<T, TFilter>
constructor TOfTypeEnumeratorFactory<T, TFilter>.Create(Owner: TList<T>);
begin
inherited Create;
FTestList := Owner;
end;
function TOfTypeEnumeratorFactory<T, TFilter>.GetEnumerator: IEnumerator;
begin
Result := GenericGetEnumerator;
end;
function TOfTypeEnumeratorFactory<T, TFilter>.GenericGetEnumerator: 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.
测试程序:
var
MyElem: TListItemBase;
MyElem1: TListItemChild1;
MyElem2: TListItemChild2;
begin
Memo1.Clear;
for MyElem in FTestList.OfType<TListItemBase>() do
begin
Memo1.Lines.Add('----------');
end;
for MyElem1 in FTestList.OfType<TListItemChild1>() do
begin
Memo1.Lines.Add('==========');
end;
for MyElem2 in FTestList.OfType<TListItemChild2>() do
begin
Memo1.Lines.Add('++++++++++');
end;
【讨论】:
以上是关于在 Delphi 中实现 List Enumerator OfType<T>的主要内容,如果未能解决你的问题,请参考以下文章
TMsgThread, TCommThread -- 在delphi线程中实现消息循环(105篇博客,好多研究消息的文章)