Yield in csharp

Understanding yield in C# – Complete Guide with Examples

In C#, yield is a special keyword used to create iterators. It helps return data one item at a time instead of returning the entire collection immediately.

This feature is extremely useful for:

  • Large data processing
  • Memory optimization
  • Lazy loading
  • Streaming data
  • File reading
  • LINQ operations
  • Infinite sequences

In this article, we will explore:

  • What yield is
  • Why it is used
  • How it works internally
  • Syntax
  • Real-world use cases
  • Advantages and limitations
  • Interview questions
  • Best practices

What is yield in C#?

yield is a keyword that allows a method to return values one-by-one during iteration instead of returning all values at once.

Normally, methods execute completely before returning data.

But iterator methods using yield:

  • Pause execution
  • Return one value
  • Resume from the same position later

This process continues until all values are returned.


Simple Definition

yield is used to create iterator methods that generate values lazily, one at a time.

Why Do We Need yield?

Imagine you have millions of records.

If you return all records at once:


public List<int> GetNumbers()
{
    List<int> numbers = new List<int>();

    for (int i = 1; i <= 1000000; i++)
    {
        numbers.Add(i);
    }

    return numbers;
}
Problems:
  • High memory usage
  • Slower startup
  • Entire collection stored in RAM

Now look at the yield version:


public IEnumerable<int> GetNumbers()
{
    for (int i = 1; i <= 1000000; i++)
    {
        yield return i;
    }
}
Benefits:
  • Values generated only when needed
  • Minimal memory usage
  • Faster execution start
  • Better performance for large data

How yield Works

When execution reaches:


yield return value;

the method:

  1. Returns the current value
  2. Pauses execution
  3. Saves current position
  4. Resumes later from the same line

This process repeats during iteration.


Visual Flow of yield


Start Method
     ↓
yield return 1
     ↓
Pause Method

Next Iteration
     ↓
Resume Method
     ↓
yield return 2
     ↓
Pause Again

Syntax of yield

C# provides two forms:

1. yield return

Returns one value at a time.


yield return value;

2. yield break

Stops iteration completely.


yield break;

Basic Example of yield


using System;
using System.Collections.Generic;

class Program
{
    static IEnumerable<int> GetNumbers()
    {
        yield return 1;
        yield return 2;
        yield return 3;
    }

    static void Main()
    {
        foreach (var number in GetNumbers())
        {
            Console.WriteLine(number);
        }
    }
}

Output


1
2
3

Important Concept – Deferred Execution

Deferred Execution

The method does not execute immediately.

Consider this example:


var data = GetNumbers();

At this point:

  • Method is NOT fully executed
  • No values are generated yet

Execution starts only when iteration begins:


foreach (var item in data)
{
    Console.WriteLine(item);
}

Execution Example


public IEnumerable<int> Demo()
{
    Console.WriteLine("Started");

    yield return 1;

    Console.WriteLine("Middle");

    yield return 2;
}

Usage:


var result = Demo();

Console.WriteLine("Before foreach");

foreach (var item in result)
{
    Console.WriteLine(item);
}

Output


Before foreach
Started
1
Middle
2

Notice: The method starts only during enumeration.


Real-World Use Cases of yield

1. Reading Large Files

Without yield, loading large files can consume huge memory.

Better Approach


public IEnumerable<string> ReadLines(string path)
{
    using var reader = new StreamReader(path);

    string line;

    while ((line = reader.ReadLine()) != null)
    {
        yield return line;
    }
}

Benefits:

  • Reads line-by-line
  • Very memory efficient
  • Suitable for huge files

2. Filtering Data


public IEnumerable<string> FilterNames(List<string> names)
{
    foreach (var name in names)
    {
        if (name.StartsWith("A"))
        {
            yield return name;
        }
    }
}

3. Pagination


public IEnumerable<int> GetData()
{
    for (int i = 1; i <= 1000000; i++)
    {
        yield return i;
    }
}

Consumer can fetch only required items.


4. Infinite Sequences


public IEnumerable<int> InfiniteNumbers()
{
    int i = 1;

    while (true)
    {
        yield return i++;
    }
}

Usage:


foreach (var number in InfiniteNumbers())
{
    Console.WriteLine(number);

    if (number == 5)
        break;
}

Output


1
2
3
4
5

Example Using Loop


public IEnumerable<int> EvenNumbers()
{
    for (int i = 1; i <= 10; i++)
    {
        if (i % 2 == 0)
        {
            yield return i;
        }
    }
}

Usage:


foreach (var num in EvenNumbers())
{
    Console.WriteLine(num);
}

Output


2
4
6
8
10

Understanding yield break

yield break is used to stop iteration immediately.


public IEnumerable<int> Numbers()
{
    yield return 1;
    yield return 2;

    yield break;

    yield return 3;
}

Output


1
2

The third value is never returned.


Return Types Allowed with yield

Methods using yield must return:

  • IEnumerable
  • IEnumerable<T>
  • IEnumerator
  • IEnumerator<T>

Most commonly:


IEnumerable<T>

Example:


public IEnumerable<int> GetNumbers()
{
    yield return 1;
}

What Happens Internally?

The C# compiler automatically converts iterator methods into a hidden state machine.

It internally creates code similar to:


IEnumerator<T>

without requiring developers to manually implement:

  • MoveNext()
  • Current
  • State tracking

Without yield

Manually implementing iterators is complicated.


class MyIterator : IEnumerator<int>
{
    // Manual state management
}

With yield

Much simpler:


yield return value;

This is why yield is widely used.


Advantages of yield

Advantage Description
Memory Efficient No need to store entire collection
Lazy Execution Data generated only when required
Cleaner Code Simplifies iterator implementation
Better Performance Faster processing for large datasets
Streaming Support Ideal for file and network operations
Easier Maintenance Less boilerplate code

Limitations of yield

Limitation Explanation
Deferred Execution Execution timing may confuse beginners
Debugging Complexity State machine generated internally
Re-execution Enumeration runs logic again
Not Allowed Everywhere Cannot use with some constructs like ref and out

Difference Between return and yield return

return yield return
Returns complete result immediately Returns one item at a time
Method ends completely Method pauses
Eager execution Lazy execution
More memory usage Memory efficient
Suitable for small collections Suitable for large/streaming data

LINQ and yield

Many LINQ methods internally rely on iterator behavior.

Examples:


Where()
Select()
Take()
Skip()

These methods use lazy execution principles similar to yield.


Async Streams with yield

Modern C# supports asynchronous iterators using:


IAsyncEnumerable<T>

Example:


public async IAsyncEnumerable<int> GetDataAsync()
{
    for (int i = 1; i <= 5; i++)
    {
        await Task.Delay(1000);

        yield return i;
    }
}

Useful for:

  • Streaming APIs
  • Real-time data
  • Asynchronous processing

Best Scenarios to Use yield

Use yield when working with:

  • Large datasets
  • File streaming
  • Database record streaming
  • LINQ-style processing
  • Pagination
  • Data pipelines
  • Infinite generators
  • Lazy loading systems

Common Interview Questions

What is yield in C#?

yield is used to create iterator methods that return values one-by-one using lazy execution.


Difference between return and yield return?

return sends all results immediately, while yield return returns items one at a time.


What is deferred execution?

Execution starts only when enumeration begins.


Which interfaces are used with yield?

  • IEnumerable
  • IEnumerable<T>
  • IEnumerator
  • IEnumerator<T>

What does yield break do?

Stops iteration immediately.


Conclusion

The yield keyword is one of the most powerful features in C# for building efficient iterators.

It helps developers:

  • Reduce memory usage
  • Improve performance
  • Simplify iterator code
  • Support lazy execution
  • Stream data efficiently

Instead of generating all results upfront, yield produces values only when needed, making it ideal for modern high-performance applications.

If you work with:

  • Large collections
  • Streaming data
  • LINQ
  • File processing
  • APIs
  • Real-time systems

then understanding yield is extremely important for writing optimized and scalable C# applications.

Comments

Popular posts from this blog

Promises in Angular

Debouncing & Throttling in RxJS: Optimizing API Calls and User Interactions

Csharp Coding - Session