2014-09-29 43 views
6

我試圖用for in迭代一個TObjectList如何爲TObjectList做些什麼?

program Project1; 

{$APPTYPE CONSOLE} 

{$R *.res} 

uses 
    System.SysUtils, Contnrs; 

var 
    list: TObjectlist; 
    o: TObject; 
begin 
    list := TObjectList.Create; 
    for o in list do 
    begin 
     //nothing 
    end; 
end. 

它無法編譯:

[dcc32錯誤] Project1.dpr(15):E2010不兼容的類型: 'TObject的'和「指針」

它好像德爾福for in結構不處理非類型化的,未降,TObjectList一個作爲枚舉目標。

如何枚舉TObjectList中的對象?

我現在在做什麼

我當前的代碼是:

procedure TfrmCustomerLocator.OnBatchDataAvailable(BatchList: TObjectList); 
var 
    i: Integer; 
    o: TObject; 
begin 
    for i := 0 to BatchList.Count-1 do 
    begin 
     o := BatchList.Items[i]; 

     //...snip...where we do something with (o as TCustomer) 
    end; 
end;  

沒有很好的理由,我希望將它更改爲:

procedure TfrmCustomerLocator.OnBatchDataAvailable(BatchList: TObjectList); 
var 
    o: TObject; 
begin 
    for o in BatchList do 
    begin 
     //...snip...where we do something with (o as TCustomer) 
    end; 
end;  

爲什麼要使用一個枚舉?正因爲。

+3

使用通用'TObjectList的''而不是TObjectList'。 – whosrdaddy 2014-09-29 15:03:06

+1

實施例做硬的方式:(http://www.remkoweijnen.nl/blog/2008/03/02/supporting-for-in-loop-in-tobjectlist-descendants/ [在循環中TObjectList後代支護] )。 – 2014-09-29 15:34:44

+1

我報道這個問題,因爲[錯誤10790(http://qc.embarcadero.com/wc/qcmain.aspx?d=10790)於2005年在2011年,它被「推遲到下一個版本。」 – 2014-09-29 17:00:43

回答

4

如何枚舉TObjectList中的對象?

要回答具體問題,這是一個介紹枚舉數的例子。 請注意,你將不得不以添加GetEnumerator函數創建的TObjectList後裔。你可以不使用類助手進行子類化,但我將其作爲感興趣的讀者的練習。

type 

TObjectListEnumerator = record 
private 
    FIndex: Integer; 
    FList: TObjectList; 
public 
    constructor Create(AList: TObjectList); 
    function GetCurrent: TObject; 
    function MoveNext: Boolean; 
    property Current: TObject read GetCurrent; 
end; 

constructor TObjectListEnumerator.Create(AList: TObjectList); 
begin 
    FIndex := -1; 
    FList := AList; 
end; 

function TObjectListEnumerator.GetCurrent; 
begin 
    Result := FList[FIndex]; 
end; 

function TObjectListEnumerator.MoveNext: Boolean; 
begin 
    Result := FIndex < FList.Count - 1; 
    if Result then 
    Inc(FIndex); 
end; 

//-- Your new subclassed TObjectList 

Type 

TMyObjectList = class(TObjectList) 
    public 
    function GetEnumerator: TObjectListEnumerator; 
end; 

function TMyObjectList.GetEnumerator: TObjectListEnumerator; 
begin 
    Result := TObjectListEnumerator.Create(Self); 
end; 

枚舉器的這種實現使用記錄而不是類。這樣做的好處是在執行for..in枚舉時不會在堆上分配額外的對象。

procedure TfrmCustomerLocator.OnBatchDataAvailable(BatchList: TObjectList); 
var 
    o: TObject; 
begin 
    for o in TMyObjectList(BatchList) do // A simple cast is enough in this example 
    begin 
     //...snip...where we do something with (o as TCustomer) 
    end; 
end; 

正如其他人所指出的那樣,有一個泛型類,它是一個更好的選擇使用,TObjectList<T>

+0

這回答了這個問題。儘管答案似乎很簡單:只是繼續使用整數索引。我只是試圖使用'for-in'來獲得樂趣;它並沒有真正添加任何東西。 – 2014-09-29 20:19:59

5

使用泛型你可以有一個類型的鏈表類(只注意到了評論,但生病完成這個無論如何)

如果你正在尋找一個很好的理由來使用TObjectList<T>因此將它爲您節省了很多類型轉換的代碼中的

program Project1; 

{$APPTYPE CONSOLE} 

{$R *.res} 

uses 
    System.SysUtils, Generics.Collections; 
Type 
    TCustomer = class 
    private 
    public 
    //Properties and stuff 
    end; 

var 
    list: TObjectlist<TCustomer>; 
    c: TCustomer; 
begin 
    list := TObjectList<TCustomer>.Create; 
    for c in list do 
    begin 
     //nothing 
    end; 
end. 
+1

你的意思是'名單:= TObjectList .Create' – 2014-09-29 16:07:21

+0

不幸的是正在使用的API提供了一個'TObjectList'。 – 2014-09-29 20:18:28

+0

@DavidHeffernan哎呀我的壞。是的,這就是我的意思 – 2014-09-30 06:33:13

3

TObjectList普查員在TList聲明,這是從TObjectList派生類。 RTL不費力地爲TObjectList宣佈更具體的枚舉器。所以你留下了TList枚舉器。其產生類型爲Pointer的項目,即由TList持有的項目的類型。

RTL設計師爲什麼不選擇TObjectList可能有幾個原因。例如,我斷定以下可能的原因:

  1. TObjectList,就像一切都在Contnrs已被棄用,在Generics.Collections由通用集裝箱已被棄用。爲什麼要花費資源修改過時的類。
  2. 即使TObjectList的枚舉器產生了TObject項,您仍然必須施放它們。一個統計員得到TObject會更有幫助嗎?
  3. 設計師簡單地忘記了這個類在添加枚舉數時存在。

你應該怎麼做。一個明顯的選擇是從Generics.Collections使用TList<T>TObjectList<T>。如果你想堅持TObjectList,你可以對它進行分類並添加一個產生了TObject的枚舉器。如果您不知道如何操作,可以從documentation瞭解如何操作。或者你可以使用繼承的枚舉器並且類型轉換它產生的指針。

在我看來,既然你願意從索引中循環,意味着你願意對代碼做不平凡的變化修改代碼迴路到了。在這種情況下,通用容器似乎是明顯的選擇。

+0

也許OP需要使用for循環而不是循環,因爲他需要在該循環內移除TObjectList中的一些對象。如果是這種情況,最簡單的方法是使用while循環而不是for循環。 Infact while循環是在統計員中使用的。 – SilverWarior 2014-09-29 15:49:06

+0

@SilverWarior您不能在for循環中更改列表,而不是在經典索引for循環中更改列表。伊恩想要使用for循環,因爲它更可讀。 – 2014-09-29 15:57:24

+0

@David,關於參數2:'x:= TObject(o)作爲TMyClass'和'x:= o作爲TMyClass',IMO仍然存在差異。 – 2014-09-29 16:03:14