Skip to footer content
Iron Academy Logo
Learn C#
Learn C#

Other Categories

Intro to Yield in C# - What it is, how to use it, and when it is useful

Tim Corey
43m 58s

When you first come across the yield keyword in C#, it can seem puzzling. How exactly does it work? When should you use yield return instead of a traditional return statement? To get a complete understanding, we’re going to walk through a detailed explanation based on Tim Corey’s excellent YouTube tutorial: "Intro to Yield in C# - What it is, how to use it, and when it is useful."

In this guide, we'll reference specific points in Tim’s video by timestamp for easier navigation and include practical examples to show how yield transforms the way you handle data streams, large collections, and lazy evaluation.

Introduction to the Yield Keyword in C

Tim starts by introducing the yield keyword and highlighting that it can often be confusing for developers encountering it for the first time. He explains that the yield statement allows a method to pause execution, maintain its state, and then continue from where it left off upon the next call. Tim emphasizes that understanding yield is critical for processing data efficiently, particularly when dealing with large datasets or implementing custom iteration logic.

Setting up a Simple Example: Class Program and Static Void Main

To eliminate distractions, Tim creates a simple Console Application in Visual Studio, called "YieldDemoApp."

Understanding Yield In Csharp 1 related to Setting up a Simple Example: Class Program and Static Void Main

What Yield Actually Does in C

Tim then dives deeper into theory. At 2:04, he describes the behavior of yield: Instead of processing an entire collection at once, the yield statement holds a spot — like putting a thumb into a book — so that execution can pause and resume later.

This behavior is crucial for deferred execution, where values are generated only when needed, rather than pre-computing everything upfront. Tim's description clearly sets the foundation for understanding how yield return works.

Writing Demo Code

In the static void Main method of the Class Program, he sets up basic bookend messages like "Start of the app" and "End of the app" using Console.WriteLine, helping to visualize the flow clearly when working with a foreach loop later.

This initial code example focuses purely on the yield implementation without involving any UI complexities.

Creating the PersonModel Class

To demonstrate, Tim creates a PersonModel class with FirstName and LastName properties and a constructor. When a PersonModel object is created, a message is printed, indicating which user was initialized. This helps visualize when objects are being created versus when they're being consumed.

Understanding Yield In Csharp 2 related to Creating the PersonModel Class

This simple generate code step sets the stage for working with custom iterators.

Building the DataAccess Class with a Traditional List Return

At 5:06, Tim moves to a DataAccess class with a GetPeople method returning IEnumerable. Initially, the return value is a List populated with three PersonModel instances: Tim Corey, Sue Storm, and Jane Smith.

Understanding Yield In Csharp 3 related to Building the DataAccess Class with a Traditional List Return

This iterator method loads all the objects immediately into memory before iteration begins — an important point Tim later contrasts with using yield.

Understanding Yield In Csharp 4 related to Building the DataAccess Class with a Traditional List Return

Demonstrating Memory Usage with List

After running the foreach loop, Tim shows that all three users are created before the first element is even read. This highlights a potential problem when dealing with large collections or large datasets — high memory usage.

Understanding Yield In Csharp 5 related to Demonstrating Memory Usage with List

Tim explains that if we had, say, a thousand users, we would have created a thousand objects even if we only needed a few, resulting in inefficient memory allocation.

Changing to Yield Return for Deferred Execution

At 10:01, Tim modifies GetPeople to use yield return instead of creating a temporary collection (a List). Each yield return statement directly emits one PersonModel at a time.

This critical code inside the method allows lazy evaluation, where the next element is generated only when needed by the foreach.

Tim also clarifies that the method's return type must be IEnumerable, and using List would defeat the purpose of deferred execution.

Debugging: How Compiler Generates Code for Yield

Tim uses breakpoints to step through the process. He shows that before the first MoveNext call, the sequence is empty. Only when foreach needs the next value does the compiler trigger the iterator block and execute the yield return num line, which initializes and returns the PersonModel.

Understanding Yield In Csharp 6 related to Debugging: How Compiler Generates Code for Yield

Tim highlights that the compiler generates special state machines under the hood to manage the paused and resumed execution.

Benefits and Efficiency of Using Yield Return

Tim explains why yield is so efficient:

  • You can fetch one record at a time.

  • You can limit the int count you need.

  • You avoid loading the entire collection into memory.

  • You improve scalability, especially when working with large file processing or data streams.

By using LINQ's .Take(2), Tim demonstrates how only two objects are initialized even though three yield return statements exist — highlighting deferred execution in action.

Practical Example: Prime Number Generator Using Yield

Tim builds a new static IEnumerableGetPrimeNumbers() method inside a Generators class. In this infinite loop, Tim uses a helper IsPrimeNumber(int number) function to check primality. If the number is prime, he uses yield return number to emit it.

This example shows that yield is critical for handling infinite sequences safely.

Without yield, the code would crash due to unlimited memory consumption. Using yield, however, deferred execution ensures that numbers are generated on demand.

Fetching Prime Numbers with Take()

Tim then shows how to safely fetch only a fixed number of prime numbers:

var primeNumbers = Generators.GetPrimeNumbers().Take(10000);
var primeNumbers = Generators.GetPrimeNumbers().Take(10000);

This code written inside static void Main efficiently fetches just 10,000 primes.

Because yield return produces numbers one-by-one, memory usage remains low.

Custom Iteration: Using GetEnumerator and MoveNext

Tim takes things further by explaining how to control iteration manually.

He creates a var iterator = primeNumbers.GetEnumerator(), then uses a for loop with int i and calls iterator.MoveNext() to fetch elements manually.

This manual approach enables custom iteration — asking for next value only when needed, and showing the method resumes exactly from where it last paused.

A Common Mistake: Using ToList() on Yielded Collections

At 36:45, Tim warns: converting a yield sequence to a List with .ToList() causes immediate full evaluation.

If you call .ToList() on an infinite sequence, you risk crashing your app.

Tim stresses that yield return is intended for lazy evaluation, and that calling .ToList() breaks this pattern by forcing full memory materialization.

When working with LINQ methods, Tim recommends being cautious about where you introduce .ToList().

Summary: Why Yield is a Powerful Tool

Tim wraps up by reinforcing that while the yield keyword adds slight overhead (holding a state machine), the benefits of reduced memory usage and lazy evaluation make it a powerful tool when working with:

  • Large datasets

  • Large files

  • Custom iterators

  • Infinite sequences

  • Data streams

  • Deferred processing

He suggests practicing with yield in different projects to develop a deeper understanding of yield return and avoid common pitfalls.

Tim concludes by inviting viewers to share how they have used yield in production code.

Conclusion

By walking through Tim Corey’s video, we’ve seen the immense benefits the yield keyword brings to C#. From creating custom iterators to managing large collections efficiently, yield return allows function returns to be smarter and more memory-efficient. Whether you're working with var number, var point, var reader, var connection, or large datasets, mastering yield can elevate your C# coding skills dramatically.

If you haven't explored using yield before, now is the perfect time to practice it through simple examples and better understand how yield return works inside the C# compiler. Do check out Tim's official YouTube Channel for more insightful videos.

Hero Worlddot related to Intro to Yield in C# - What it is, how to use it, and when it is useful
Hero Affiliate related to Intro to Yield in C# - What it is, how to use it, and when it is useful

Earn More by Sharing What You Love

Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!