【问题标题】:C# yield return not returning an item as expectedC# yield return 未按预期返回项目
【发布时间】:2010-03-23 22:51:45
【问题描述】:

我有以下代码:

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 捕获了。

有人可以解释发生了什么并给出解决方案吗?

【问题讨论】:

  • 如果只在 ProcessQueue 中使用 while 循环而不是使用枚举器,代码会更简单。枚举器非常方便,但对于简单的循环处理来说,它们可能是多余的。
  • 好评论 - 虽然我通过一系列重构来到了上面,我只是陷入了好奇的追逐中。

标签: c# yield


【解决方案1】:

你的程序完全按照你的指示去做:如果Count &gt; 0,它会产生一个项目 - 否则会产生零个项目。

要返回项目直到队列变空,尝试:

while (_messageQueue.Count > 0)

【讨论】:

  • @Obalix:你错了。永远不会有竞争条件,因为在 PerformAction 期间从同一线程添加项目。问题不在于从其他线程访问队列——yield 不会神奇地将代码变成多线程。
  • 竞争条件在哪里??
  • @Jiho:如果队列可以被多个线程同时访问和/或修改,您发布的代码将无法按预期工作。
  • 已注意到,但目前我不关心线程。至于我关于比赛条件的问题,我的意思是我没有看到 Obalix 在哪里谈论比赛条件。是否以某种方式删除了?
  • @Jiho:“注意到了,但我现在不关心线程”:我想这正是他删除它的原因。
【解决方案2】:

yield return 实际上会暂停执行并进行假返回(它产生一个值),直到请求下一个。在这种情况下,您会检查计数是否 > 0,然后产生下一个值。当请求下一个时,您的 if 语句不再检查,它返回到 yield return 之后的行,这是方法的结尾,因此它完成了。

【讨论】:

  • 我更喜欢这个解释;我认为这更清楚
【解决方案3】:

“YIELD”的定义

在迭代器块中用于向枚举器对象提供值或发出迭代结束的信号。

我有一个很好的阅读语法语句错误的记录,但我认为这意味着它必须在一个迭代器块中,而你写的不是。

也许将您的代码更改为;

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

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-08
    • 1970-01-01
    • 2012-10-05
    • 2017-03-31
    • 1970-01-01
    • 2016-08-14
    • 2011-03-26
    • 2020-07-06
    相关资源
    最近更新 更多