Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
IT Security DownloadsGitHub Release: openclaw/openclaw v2026.7.35 (20.09.2026)(20.09.2026 um 21:37 Uhr)
IT Security DownloadsGitHub Release: openclaw/openclaw v2026.7.35 (20.09.2026)(20.09.2026 um 21:37 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

The Hidden Cost of yield in C#: What the Compiler Doesn't Tell You

Reagiere als Erste:r — dein Feedback zählt!

Most C# developers know how to use yield return. Few understand what actually happens after compilation.
If you've ever written something like this:

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

it looks almost magical.

No collection.
No list allocation.
No iterator implementation.
Yet somehow the method returns an IEnumerable.
So what is really happening?
The answer is one of the most elegant compiler transformations in the entire .NET ecosystem.
Let's open the hood.

The Illusion

Most developers imagine the previous code executes like this:

Call method
↓

Return 1
↓

Pause

↓

Return 2

↓

Pause

↓

Return 3

That isn't what happens.
C# methods cannot actually pause execution.
Instead, the compiler completely rewrites your method into something entirely different.

The Compiler Creates a State Machine

Your tiny method becomes a hidden class similar to this:

private sealed class GetNumbersIterator :
    IEnumerable<int>,
    IEnumerator<int>
{
    private int _state;
    private int _current;

    public bool MoveNext()
    {
        switch (_state)
        {
            case 0:
                _current = 1;
                _state = 1;
                return true;

            case 1:
                _current = 2;
                _state = 2;
                return true;

            case 2:
                _current = 3;
                _state = -1;
                return true;

            default:
                return false;
        }
    }

    public int Current => _current;
}

Your original method no longer exists.

Instead, it simply returns:

return new GetNumbersIterator();

Every yield return becomes another state inside MoveNext().

Why Local Variables Don't Disappear

Consider this code:

IEnumerable<int> Squares()
{
    int x = 1;

    while (x <= 3)
    {
        yield return x * x;
        x++;
    }
}

After the first yield, the method "pauses."

But where is x stored?

Not on the stack.

The original stack frame has already disappeared.

Instead, the compiler promotes local variables into fields:

private int _x;

The iterator object now owns every variable that must survive between iterations.

This is why iterator methods can remember where they left off.

Heap Allocation Happens

Many developers assume yield is allocation-free because it doesn't create a list.

That's only partially true.
Instead of allocating an entire collection, the runtime allocates the iterator object itself.

Without yield

List<int>
 ├──1
 ├──2
 ├──3

With yield

Iterator Object
    │
MoveNext()

One allocation replaces another. Usually that's a good tradeoff,
But it is not free.

Lazy Execution Changes Everything

Nothing executes here:

var numbers = GetNumbers();

The method body hasn't even started.

Execution begins only when enumeration starts:

foreach(var n in numbers)
{
    Console.WriteLine(n);
}

This surprises many developers.

If your iterator contains logging:

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

    yield return 1;
}

then this prints nothing:

var nums = GetNumbers();

Only this triggers execution:

nums.First();

Exceptions Behave Differently

Because execution is deferred:

var numbers = GetNumbers();

won't throw exceptions inside the iterator.

Instead, the exception appears later:

foreach(var n in numbers)

This delayed behavior can make debugging surprisingly confusing.

Why yield Often Beats Returning a List

Imagine reading a million rows from a database.

Returning a list means:

Read everything

↓

Allocate huge list

↓

Return list

Using yield becomes:

Read row

↓

Return row

↓

Read next row

↓

Return row

Memory usage remains almost constant.

This is one of the biggest reasons LINQ is so efficient.

But There Are Trade-offs

yield isn't always the right tool.

Consider these limitations:

You cannot easily iterate multiple times over one enumerator.
Random access is impossible.
Deferred execution can hide exceptions.
Iterator objects still allocate memory.
Complex iterator logic can become difficult to debug.

Understanding these trade-offs helps you decide when laziness is an optimization—and when it becomes a source of complexity.

Visualizing the State Machine


┌────────────┐
│ Start      │
└─────┬──────┘
      │
      ▼
yield return 1
      │
      ▼
State = 1
      │
MoveNext()
      ▼
yield return 2
      │
      ▼
State = 2
      │
MoveNext()
      ▼
yield return 3
      │
      ▼
Finished

The compiler converts your seemingly linear method into a deterministic state machine that advances one step at a time.

Final Thoughts

yield is one of C#'s most elegant language features—not because it magically pauses methods, but because the compiler quietly rewrites your code into a sophisticated iterator object.

Once you understand that:

  • yield creates a compiler-generated class
  • local variables become heap fields
  • execution is deferred until enumeration
  • and each yield return becomes a new state

the behavior of iterators suddenly becomes predictable.
The next time you write yield return, remember: you're not writing an iterator—you’re asking the C# compiler to write one for you.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten The Hidden Cost of yield in C#: What the Compiler Doesn't Tell You

Thematisch verwandte Begriffe: Hidden, Cost, yield, What · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-93956 | A flaw has been found in olivier-ls PHP-FTS up to 1.1.2. Affected by thi…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick