用Delphi 2010過濾枚舉,讓我們說我有聲明如下一類:更好的方式來實現對從TList <TMyObject>
TMyList = TList<TMyObject>
對於這個列表德爾福好心爲我們提供了一個枚舉,所以我們可以這樣寫這樣的:
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;
使用這個我終於可以寫:
你知不知道這樣做的更好的辦法?也許德爾福支持一種直接調用GetEnumerator的方法?
後來編輯:
我決定用使用匿名方法實現枚舉和使用賈布爾的「記錄」工廠還保存其他類的羅伯特·愛的想法。這使我可以創建一個全新的枚舉器,並使用代碼完成,只需在函數中使用幾行代碼,不需要新的類聲明。
這裏是我的通用枚舉的聲明方式,在庫單元:
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;
感謝這一點,現在實現對類的枚舉器支持變得更容易了。如果你想使用'for obj in list do'之類的東西,那麼只需像這樣聲明GetEnumerator():'function GetEnumerator:TEnumGenericAnonim',並且在實現中只需在Create語句的最後添加'.GetEnumerator'即可。 –
Sharken
2012-02-20 07:53:52