Lazy Loading By Using C# Yield Statements

I keep forgetting about that fun little yield statement we’ve got in C#. It’s that one that lets you magically create an enumerator out of a normal method.

The other day I was feeling lazy. I had a bunch of views that all shared the same model which allowed for a bunch of different editors for different types of data. Some of them needed a list of features pulled from the database. The easy thing to do would be to just slap that feature query result onto the model, but it only needed to be used by a single view and it was an expensive query with some other nonsense happening to the list in the controller, so it was slowing down all other views unnecessarily.

I then remembered the yield statement and wondered whether it would lazy-load, hoping that my slow loading method would never be called unless the view actually used it. It worked!

static void Main(string[] args)
{
    Console.WriteLine("Test 1 (we're not enumerating this time)");
    var foo1 = GetFeatures();

    Console.WriteLine("Test 2 (just peeking in the enumeration)");
    var foo2 = GetFeatures();
    Console.WriteLine("First entry in list: " + foo2.First());
}
        
// this is the expensive method
static IEnumerable<string> GetFeatures()
{
    Console.WriteLine("GetFeatures was called");

    // just pretend this is an expensive query
    var expensiveList = new string[] { "a", "b", "c", "d" };

    //and pretend we're doing something more complex
    foreach (var item in expensiveList)
        yield return item;
}

  <p>
    And the output:
  </p>

  <div style="color:#eee;background-color:#333;font-family:Courier New, sans serif;margin-top:1em;margin-bottom:1em;padding:.5em;">
    Test 1 (we&#8217;re not enumerating this time)<br /> Test 2 (just peeking in the enumeration)<br /> GetFeatures was called<br /> First entry in list: a<br /> Press any key to continue . . .
  </div>

  <p>
    Of course, all this lazy loading nonsense could be skipped if we just built the query logic inside the model&#8217;s collection <em>get</em> method, but that wouldn&#8217;t be very MVCy, now, would it? I&#8217;d rather set the list in the controller.
  </p>