tags:

views:

166

answers:

3

I have following code:

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

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

Initially there is one item in the queue as ProcessQueue is called. During PerformAction, I would add more items to _messageQueue. However, the foreach loop quits after the initial item and does not see the subsequent items added.

I sense that somehow the initial state of the queue is being captured by yield.

Can someone explain what is happening and give a solution?

+5  A: 

Your program does exactly what you instructed to do: it yields one item if Count > 0 - and yields zero items otherwise.

To return items until the queue becomes empty, try:

while (_messageQueue.Count > 0)
andras
@Obalix: you are wrong. There will never be a race condition, since items are added during PerformAction from the same thread. The question is not about accessing the queue from other threads - and `yield` will not turn the code magically into multi-threaded.
andras
Where is the bit about race condition??
Jiho Han
@Jiho: if the queue can be accessed and/or modified by multiple threads simultenously, the code you have posted will not work as expected.
andras
Noted but I don't have a concern for threading at the moment.As for my question regarding the race condition, I meant that I didn't see where Obalix talks about race conditions. Was that deleted somehow?
Jiho Han
@Jiho: "Noted but I don't have a concern for threading at the moment": I suppose that this is exactly why he deleted it.
andras
+1  A: 

yield return actually pauses execution and does a fake return (it yields a value) until the next one is requested. In this case, what happens is you check if the count is > 0 and then yield the next value. When the next one is requested, your if statement isn't checked again, it returns to the line after the yield return which is the end of the method and thus it's done.

Davy8
I like this explanation better though; it's clearer in my opinion
Jiho Han
A: 

The definition of "YIELD"

Used in an iterator block to provide a value to the enumerator object or to signal the end of iteration.

I have an excellent record of reading syntax statements wrong but I think this means it has to be in an iterator block and the one you wrote is not.

Perhaps change your code to;

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

}
Tom Groszko