使用Delphi 2010,假设我声明了一个类如下所示:
使用这个,我终于可以写下去了:
你知道更好的方法吗?也许Delphi支持直接使用参数调用GetEnumerator的方法吗?
后来我决定采用Robert Love的想法,使用匿名方法实现枚举器,并使用gabr的“record”工厂来保存另一个类。这使我可以仅仅使用几行代码在函数中创建全新的、完整的带有代码的枚举器,而无需声明新的类。
下面是我的通用枚举器在库单元中的声明:
TMyList = TList<TMyObject>
对于这个列表,Delphi友好地提供了一个枚举器,所以我们可以这样写:
var L:TMyList;
E:TMyObject;
begin
for E in L do ;
end;
问题在于,我想要写下这句话:
var L:TMyList;
E:TMyObject;
begin
for E in L.GetEnumerator('123') do ;
end;
我的需求是能够根据某些条件为同一列表提供多个枚举器。不幸的是,for X in Z
的实现需要一个名为 Z.GetEnumerator
的函数,没有参数,返回给定的枚举器!为了绕过这个问题,我定义了一个实现“GetEnumerator”函数的接口,然后我实现一个实现该接口的类,最后我在 TMyList 上编写一个返回接口的函数!而我返回一个接口是因为我不想手动释放非常简单的类... 无论如何,这需要大量的打字。下面是示例:
TMyList = class(TList<TMyObject>)
protected
// Simple enumerator; Gets access to the "root" list
TSimpleEnumerator = class
protected
public
constructor Create(aList:TList<TMyObject>; FilterValue:Integer);
function MoveNext:Boolean; // This is where filtering happens
property Current:TTipElement;
end;
// Interface that will create the TSimpleEnumerator. Want this
// to be an interface so it will free itself.
ISimpleEnumeratorFactory = interface
function GetEnumerator:TSimpleEnumerator;
end;
// Class that implements the ISimpleEnumeratorFactory
TSimpleEnumeratorFactory = class(TInterfacedObject, ISimpleEnumeratorFactory)
function GetEnumerator:TSimpleEnumerator;
end;
public
function FilteredEnum(X:Integer):ISimpleEnumeratorFactory;
end;
使用这个,我终于可以写下去了:
var L:TMyList;
E:TMyObject;
begin
for E in L.FilteredEnum(7) do ;
end;
你知道更好的方法吗?也许Delphi支持直接使用参数调用GetEnumerator的方法吗?
后来我决定采用Robert Love的想法,使用匿名方法实现枚举器,并使用gabr的“record”工厂来保存另一个类。这使我可以仅仅使用几行代码在函数中创建全新的、完整的带有代码的枚举器,而无需声明新的类。
下面是我的通用枚举器在库单元中的声明:
TEnumGenericMoveNext<T> = reference to function: Boolean;
TEnumGenericCurrent<T> = reference to function: T;
TEnumGenericAnonim<T> = class
protected
FEnumGenericMoveNext:TEnumGenericMoveNext<T>;
FEnumGenericCurrent:TEnumGenericCurrent<T>;
function GetCurrent:T;
public
constructor Create(EnumGenericMoveNext:TEnumGenericMoveNext<T>; EnumGenericCurrent:TEnumGenericCurrent<T>);
function MoveNext:Boolean;
property Current:T read GetCurrent;
end;
TGenericAnonEnumFactory<T> = record
public
FEnumGenericMoveNext:TEnumGenericMoveNext<T>;
FEnumGenericCurrent:TEnumGenericCurrent<T>;
constructor Create(EnumGenericMoveNext:TEnumGenericMoveNext<T>; EnumGenericCurrent:TEnumGenericCurrent<T>);
function GetEnumerator:TEnumGenericAnonim<T>;
end;
以下是使用它的方法。在任何类上,我可以添加一个像这样的函数(我有意创建了一个不使用 List<T>
的枚举器来展示这个概念的强大性):
type Form1 = class(TForm)
protected
function Numbers(From, To:Integer):TGenericAnonEnumFactory<Integer>;
end;
// This is all that's needed to implement an enumerator!
function Form1.Numbers(From, To:Integer):TGenericAnonEnumFactory<Integer>;
var Current:Integer;
begin
Current := From - 1;
Result := TGenericAnonEnumFactory<Integer>.Create(
// This is the MoveNext implementation
function :Boolean
begin
Inc(Current);
Result := Current <= To;
end
,
// This is the GetCurrent implementation
function :Integer
begin
Result := Current;
end
);
end;
以下是我如何使用这个新枚举器的方法:
procedure Form1.Button1Click(Sender: TObject);
var N:Integer;
begin
for N in Numbers(3,10) do
Memo1.Lines.Add(IntToStr(N));
end;