Mastering yield in C#

Roman Fairushyn
3 min readJan 17, 2024

--

Introduction

Welcome to a comprehensive exploration of the yield keyword in C#. As seasoned software engineers, you're likely familiar with the fundamentals of C#, but the yield keyword often remains an underutilized and misunderstood gem. This post aims to demystify yield, showcasing its power and flexibility in various real-world scenarios. By integrating yield into your C# toolkit, you can write more efficient, readable, and maintainable code, elevating your programming prowess for your next technical interview or challenging project.

Understanding yield in C#

At its core, yield is a powerful keyword used in iterator methods to provide a simple way to return an enumerable sequence, one element at a time. Unlike traditional collection-returning methods, yield enables state persistence across iterations, allowing for lazy evaluation and increased performance, especially when dealing with large datasets or complex data structures.

Basic Syntax

public IEnumerable<int> GetNumbers()
{
for (int i = 0; i < 10; i++)
{
yield return i;
}
}

In this example, GetNumbers generates a sequence of integers from 0 to 9. Each iteration of the for loop uses yield return to provide the next number in the sequence.

Real-World Scenarios

Scenario 1: Lazy Loading

Imagine a scenario where you need to process a large dataset, say a file with millions of lines. Loading the entire dataset into memory can be inefficient and resource-intensive. Here, yield comes to the rescue:

public IEnumerable<string> ReadLargeFile(string filePath)
{
using (var file = new StreamReader(filePath))
{
string line;
while ((line = file.ReadLine()) != null)
{
yield return line;
}
}
}

This method reads the file line by line, returning each line as it’s read. This approach is memory efficient as it only holds one line in memory at a time.

Scenario 2: Complex Business Logic

Consider an application that filters a collection of products based on some complex business logic. Using yield, you can create a clear and efficient filtering process:

public IEnumerable<Product> FilterProducts(
IEnumerable<Product> products, Criteria criteria
)
{
foreach (var product in products)
{
if (MeetsCriteria(product, criteria))
{
yield return product;
}
}
}

This method iterates through the products, yielding only those that meet the specified criteria. This approach simplifies complex filtering logic and improves code readability.

Scenario 3: Infinite Sequences

yield can be used to create infinite sequences, useful in scenarios like generating an endless stream of data:

public IEnumerable<int> GenerateInfiniteSequence()
{
int i = 0;
while (true)
{
yield return i++;
}
}

This method generates an endless sequence of integers. Such an approach can be particularly useful in simulations or streaming data applications.

Scenario 4: Stateful Iterations

yield maintains state between iterations. This feature can be leveraged in scenarios where the state of each iteration is important, like in a state machine:

public IEnumerable<State> RunStateMachine(State initialState)
{
State currentState = initialState;
while (currentState != null)
{
yield return currentState;
currentState = currentState.NextState();
}
}

This method uses yield to walk through the states of a state machine, maintaining the current state between each call.

Conclusion

yield in C# is a potent tool that, when used correctly, can significantly enhance the efficiency and readability of your code. It is particularly useful in scenarios involving large data sets, complex logic, infinite sequences, and stateful iterations. By mastering yield, you equip yourself with an advanced skill that not only impresses in technical interviews but also proves invaluable in solving real-world programming challenges. As you continue to develop and refine your C# expertise, remember to explore and integrate these powerful features into your coding repertoire.

--

--