2013-02-27 68 views
3

我知道有很多方法可以做得更好,但是我在現有代碼中看到了它,現在我想知道這是否會產生任何負面影響。請注意刪除後的分號。因此,我一般不關心迭代器,但是我關心意外的行爲( - >潛在的異常)。在休息前刪除foreach

foreach (var item in items) 
{ 
    //do stuff 
    if (item.IsSomething) 
    { 
     items.Remove(item); //is this safe??? 
     break; 
    } 
} 

難道它也有可能以我不指望的方式優化某些東西嗎?

+2

如果不繼續枚舉,那麼可以這樣做。 – 2013-02-27 08:42:42

+5

這是一個很好的問題,只需運行一次代碼就可以回答。告訴我們它的行爲方式 – VladL 2013-02-27 08:43:41

+0

已經使用了相當長的一段時間。所以它適用於我的情況。我只是想確保它是一個安全有效的模式(我將來不會使用它)。如果沒有'break', – Dunken 2013-02-27 08:47:40

回答

7

編譯器在finally塊中執行的枚舉器上生成對Dispose()的調用,但這應該不成問題。如果您在刪除項目後立即執行break,則不會發生任何錯誤,因爲您不再使用枚舉器。

如果你想要做雖然它以不同的方式(風格的原因,或其他),你可以這樣做:

var item = items.FirstOrDefault(i => i.IsSomething); 
if (item != null) { 
    items.Remove(item); 
} 

這也是一個有點短:)(我假設在這裏使用的是參考或可收集的類型)。

+1

+1,但是如果'items'是'''''''''''''''這個代碼有什麼問題? – 2013-02-27 08:51:16

+0

@IlyaIvanov結構將需要不同的方法,因爲結構的默認值仍然是該結構的有效實例,只是所有字段都初始化爲默認值(結構不能爲空)。例如,'int'被定義爲一個struct/value類型,它的默認值是0(不是'null'),它仍然是一個有效的數字。 – Botz3000 2013-02-27 08:55:39

+1

@IlyaIvanov:正確的,可以使用'Where' +'Any' +'First'的結構體:var itemsWithSomething = items.Where(i => i.IsSomething); bool hasSomething = itemsWithSomething.Any();' – 2013-02-27 08:58:02

2

編譯器和與您的應用程序保持聯繫的其他一切都可以保證SC-DRF(數據無競爭程序的順序一致性),所以您不會看到您編寫的程序和程序之間的區別執行(這是任何東西,但相同)。假設items不在多個線程之間共享,這是完全安全的寫入,沒有意外的行爲,而不是在循環之外調用Remove

-1

然後ü可以做到這一點 - 它與大型列表(假設實體框架)打交道時更加高效

var reducedList = items.where(a=>a.IsSomething).toList(); 
foreach(var item in reducedList) 
{ 
    reducedList.Remove(item); 
} 

這降低了foreach循環迭代

+0

似乎奇怪的是在第一次迭代之後使用循環並中斷。 – 2013-02-27 08:52:48

+0

@Jasd你現在不需要右鍵中斷 – tariq 2013-02-27 08:57:14

+0

那麼問題是你仍然在迭代列表,同時從中刪除項目。這並不能解決問題。 (你甚至現在有2個循環) – RvdK 2013-02-27 08:58:15

1

在迭代不能更改列表在foreach內。

底層集合在枚舉時不能被修改。一種標準的方法是將項目保留在第二個列表中,然後在枚舉項目之後,然後從項目中刪除每個項目。

+0

我在迭代時更改列表。我給的例子可能是不好的做法,但它的工作原理。 – Dunken 2013-03-08 14:40:14

+0

是的它的工作原理,但在未來的迭代可能會造成問題。 – 2013-03-09 05:37:01