Crash course: the yield keyword

Within this article I want to give an introduction to the yield keyword because I have seen that a lot of software developers don’t know or don’t use this keyword and therefore they miss his nice and powerful features.

Since .NET version 2.0 the yield keyword is available in C#. It can be used on enumerable objects. These objects implement the IEnumerable interface. IEnumerable means the object is a container type with a set of elements.

 
IEnumerable

Let’s create a short example to show this interface. Within a method a file should be read. The file contains several lines of text. These lines of text will be read and stored into a container object. But the method should not return this concrete object. Instead the generic IEnumerable interface is used as return parameter. By using this generic interface the method is reusable in a lot of situations because it is no longer bound to a specific container object.

The test file ‘test.txt’ contains the following content (four lines of text):
Hello World,
This is a
testfile for
the ‚yield‘ keyword.

 
The following console application shows a possible implementation of the method to read the file. Furthermore the method is used within a loop to iterate over the content of the file.

static void Main(string[] args)
{
    string fileName = @"C:\test.txt";

    foreach (string line in ReadFile(fileName))
    {
        Console.WriteLine("Main: " + line);
    }

    Console.ReadKey();
}

private static IEnumerable ReadFile(string fileName)
{
    List<string> lines = new List<string>();

    using (StreamReader reader = new StreamReader(fileName))
    {
        while (reader.EndOfStream == false)
        {
            Console.WriteLine("ReadFile: read...");
            lines.Add(reader.ReadLine());
        }
    }

    return lines;
}

 
The application will create the following output within the console:
ReadFile: read…
ReadFile: read…
ReadFile: read…
ReadFile: read…
Main: Hello World,
Main: This is a
Main: testfile for
Main: the ‚yield‘ keyword.

 
Yield

As you can see within the demo application, the function to read the file is implemented in a very basic and not optimized way. It will read the whole file and store the data in a container object and afterwards the calling main method will iterate over this container object. If you want to read large files, this additional step to store and forward the data may result in performance or memory issues.

A more elegant solution may be created by using the yield keyword. As soon as a method uses IEnumerable as return value, the yield keyword is available. It will change the execution of the method in a fundamental way. If the method is used in a loop, the execution of the method will be interrupted by the yield return command. This command will return the given value as return value of the method. On the next iteration of the calling loop the method will not start at the beginning. Instead it will continue the work behind the yield return command and execute the method till the next yield return and therefore the interruption point is reached. If the end of the method is reached the calling loop will be finished. This end of the loop can also be triggered by using the yield break command.

The following source code shows the modified console application. Instead of a container object the function to read the file will now use the yield keyword.

static void Main(string[] args)
{
    string fileName = @"C:\test.txt";

    foreach (string line in ReadFile(fileName))
    {
        Console.WriteLine("Main: " + line);
    }

    Console.ReadKey();
}

private static IEnumerable ReadFile(string fileName)
{
    using (StreamReader reader = new StreamReader(fileName))
    {
        while (reader.EndOfStream == false)
        {
            Console.WriteLine("ReadFile: read...");
            yield return reader.ReadLine();
        }
    }
}

 
As described, this implementation will change the way how the method is executed. The yield keyword will interrupt the method and return the result during the iterations of the calling loop. Therefore the application will create the following output within the console:
ReadFile: read…
Main: Hello World,
ReadFile: read…
Main: This is a
ReadFile: read…
Main: testfile for
ReadFile: read…
Main: the ‚yield‘ keyword.

 
Yield and Exception Handling

The yield keyword will interrupt the execution of a method and continue the method in the next iteration of the calling loop. This changed execution of the application is not allowed in combination with error handling. Therefore the yield keyword cannot be used in a catch-block or a try-block with a following catch-block. If you use a try-finally-block without a catch-block, then it is allowed to use the yield keyword within the try-block.

 
Summary

It is a standard programming use case to iterate over enumerable elements. The yield keyword offers an elegant way to implement such use cases. It allows a resource saving iteration even over very large number of elements. Therefore also the .NET framework heavily uses the yield keyword. For example the delayed execution of LINQ commands is based on the yield keyword.

Werbung
Dieser Beitrag wurde unter .NET, C#, Crashkurs abgelegt und mit , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit deinem WordPress.com-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s