Advanced CSharp – yield

tran-land-05 Have you ever had a situation arise where you want to create a function that returns a collection of results and you want the results to be listed in a for each loop? 

Sure you have.  And I bet I know what your code looked like too:

 

 

public ArrayList CollectionFunction()
{
    ArrayList ar = new ArrayList();
    for (int i = 0; i < 10; i++)
    {
        ar.Add(i * (i + 1));
    }
    return ar;
}

public void CollectionEach()
{
    foreach (object o in CollectionFunction())
        Console.Write(o.ToString());
}

But did you know there is a much easier way to write this code and, as it turns out, it’s much more efficient too.

Instead of creating an array in the CollectionFunction() we can have CSharp take care of all the details by using the yield statement in our loop and making our CollectionFunction return IEnumerable instead of the ArrayList.

Here is the modified code:

public IEnumerable CollectionFunction()
{
    for (int i = 0; i < 10; i++)
    {
        yield return (i * (i + 1));
    }
}

public void CollectionEach()
{
    foreach (int i in CollectionFunction())
        Console.Write(i.ToString());
}

What happens under the hood is that a class is created to implement the behavior we’ve described in the code, meaning that the computation actually occurs AS we are looping through the IEnumerable object rather than building up a list, returning it, and then looping through the results.

Related Post

  • What is the global keyword in CSharp?What is the global keyword in CSharp? During the Christmas break, I received the following question: What does C# global:: actually do? Code example, from table adapter code: [global::System.CodeDom.Compiler.GeneratedCodeAttribute(...
  • CSharp’s Property ShortcutsCSharp’s Property Shortcuts There are a lot of nice shortcuts in the CSharp language that most of us never use.  But if you take the time to learn them, you can be as productive as a student I had who had learned all the keyb...
  • Delegates in .NETDelegates in .NET I received the following question: What is a delegate?  What problem does it solve?  and When might I use a delegate? A delegate is essentially a function pointer.  We have used function poi...
  • using – There’s more there than you are usingusing – There’s more there than you are using If you've spent more than a day programming in CSharp, you have already discovered the need for the using directive: using System; using System.Collections.Generic; using System.Text.RegularExpr...
  • Two Interfaces. Same Method. Two meanings.Two Interfaces. Same Method. Two meanings. We've discussed interfaces before, but today I want to dig a little deeper.  I'm going to assume for now that you already know what an interface is and that you know how to implement one on a clas...
  • Rick Foster

    I stumbled upon the yield statement a while ago – absolutely love it and I even considered asking you to write it up. :) But there is an issue with type safety if you are not using System.Collections.Generic. The foreach loop would still compile if written this way:

    foreach (DirectoryInfo i in CollectionFunction())

    Using generics would force you to define IEnumerable:

    public IEnumerable CollectionFunction()

    You would then be prevented from returning or receiving anything other than an int.

    Thank you for a great blog!
    Rick

  • Rick Foster

    Hmm – looks like the lt and gt were stripped from my code. Amendment:

    public IEnumerable<int> CollectionFunction()