Queue is Always Empty Using yield return

I ran into an issue in a C# application the other day. Thankfully I figured out what was going wrong right away, but it could have turned into a big headache potentially.

The View was strongly typed as IEnumerable<string> and looked something like this:

<% if(Model.Any()) { %>
<ul id="messages">
<% foreach (var message in Model) { %>
    <li><%: message %></li>
<% } %>
</ul>
<% } %>

The code behind for putting the Model into the view was also pretty simple:

<pre>
public ActionResult Messages()
{
return PartialView(messageService.GetMessages());
}

The implementation of MessageService was also very simple:

<pre>
public IEnumerable<string> GetMessages()
{
while (Queue.Count > 0)
yield return Queue.Dequeue();
}

I could set a breakpoint and see messages being queued up, but the list items weren't being rendered on the page. See the problem?

The issue isn't in the Messages() action or the GetMessages() method. In the view, when .Any() is called, it will enumerate the collection and dequeue all the messages. After that happens, there is nothing to loop through in the foreach. This was fixed easy enough with the following in MessageService:

<pre>
public IEnumerable<string> GetMessages()
{
return GetDequeuedMessages().ToArray();
}

private static IEnumerable<string> GetDequeuedMessages()
{
while (Queue.Count > 0)
yield return Queue.Dequeue();
}

Hopefully this helps you from pulling your hair out if you didn't catch it right away!

Related:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Chris Missal

Oh hey, I'm a Senior Consultant for Headspring in Austin, TX. I've been working in software professionally since 2006 and I really, really love it. I'm mostly in the Microsoft world, but enjoy building computer things of all sorts (to be vague). When I'm not slinging code, I'm probably out and about slinging discs, bowling balls, or good beer with great friends.
This entry was posted in ASP.NET MVC, LINQ. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Andy Rose

    Interesting issue, however as the call to Any() will stop iterating as soon as it returns a valid item (in this case as no filtering has been passed in this will be the first item) won’t this just remove one item from the Queue rather than emptying it altogether? Obviously not ideal but not quite what you described.

    • Anonymous

      Very good point Andy! I think I only had one item in my queue when I was running into this and forgot about how .Any() works for a moment. If I try with more than one, it does Dequeue one, and give a count one less than it should. Good catch, thanks!