2010-03-23 75 views
2

我有下面的代碼沒有返回一個項目:C#收益率回報預期

private void ProcessQueue() 
{ 
    foreach (MessageQueueItem item in GetNextQueuedItem()) 
     PerformAction(item); 
} 

private IEnumerable<MessageQueueItem> GetNextQueuedItem() 
{ 
    if (_messageQueue.Count > 0) 
     yield return _messageQueue.Dequeue(); 
} 

最初沒有在隊列中ProcessQueue一個項目被調用。 在PerformAction期間,我會向_messageQueue添加更多項目。但是,foreach循環在初始項目之後退出,並且看不到後續的項目添加。

我感覺到某種方式隊列的初始狀態被yield所捕獲。

有人可以解釋發生了什麼,並提供解決方案嗎?

+1

如果您只是在ProcessQueue中使用while循環而不是使用枚舉器,代碼會更簡單。枚舉器非常方便,但對於簡單的循環處理而言,它們可能過於矯枉過正。 – 2010-03-23 23:20:16

+0

好評 - 雖然我通過一系列重構來了解上述情況,但我只是陷入了好奇心的追逐之中。 – 2010-03-24 02:41:59

回答

6

您的程序完全按照您的指示進行操作:如果Count > 0產生一個項目 - 否則返回零項。

要返回項目直到隊列變空,嘗試:

while (_messageQueue.Count > 0) 
+0

@Obalix:你錯了。永遠不會有競爭條件,因爲項目是在PerformAction期間從同一個線程添加的。問題不在於從其他線程訪問隊列 - 而且yield不會將代碼神奇地變成多線程。 – 2010-03-23 23:28:34

+0

關於比賽狀況的一點在哪裏? – 2010-03-24 02:45:18

+0

@Jiho:如果隊列可以被多個線程同時訪問和/或修改,那麼您發佈的代碼將無法按預期工作。 – 2010-03-24 12:20:56

1

yield return實際上暫停執行,並做了假的回報(產生一個值),直到下一個請求。在這種情況下,你會檢查計數是否大於0,然後產生下一個值。當請求下一個請求時,你的if語句不再被檢查,它返回到yield return之後的行,這是方法的結束,因此完成。

+0

雖然我更喜歡這個解釋;我認爲這更清楚 – 2010-03-24 02:44:24

0

「產量」

在迭代器塊用於提供一個值,以枚舉器對象或以信號迭代結束時的定義。

我有閱讀語法錯誤的優秀記錄錯誤,但我認爲這意味着它必須位於迭代器塊中,而您所寫的不是。

也許改變你的代碼;

foreeach (MessageQueItem item In GetNextQuedItem() 
{ 
    if (_messageQueue.Count > 0) 
    { 
     yield return _messageQueue.Dequeue(); 
    } else { 
     yield break; 
    } 

}