2010-03-23 74 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; 
    } 

}