CodeGym /Kurse /C# SELF /Variable Capture durch lokale Funktionen

Variable Capture durch lokale Funktionen

C# SELF
Level 11, Lektion 5
Verfügbar

1. Einführung

Scope nochmal erklärt

Stell dir vor, Variablen sind Mitarbeiter in einem großen Büro, und Methoden, Schleifen und Codeblöcke sind die Räume und Büros. Manche Mitarbeiter dürfen nur in ihr eigenes Zimmer, andere ins ganze Gebäude. Wo sich wer aufhalten darf – das ist der Scope (scope).

Der Scope bestimmt, wo eine deklarierte Variable im Programm "sichtbar" ist und wo du sie benutzen kannst.

Die wichtigsten Arten von Scopes

In C# gibt es im Wesentlichen diese Scopes:

Scope Beispiel Wo ist die Variable sichtbar?
Lokal Innerhalb einer Methode oder eines Blocks Nur innerhalb dieses Blocks
Methodenparameter In der Methodensignatur Nur innerhalb der Methode
Klassenvariable (Feld) Im Klassentext außerhalb von Methoden In allen Methoden dieser Klasse
Variable in Schleife/Bedingung Innerhalb von
{}
einer Schleife/if
Nur innerhalb dieser
{}

Beispiel mit Erklärungen

public class Office
{
    
  
int gebaeudeNummer = 50; // Feld der Klasse: sichtbar in allen Methoden public void PrintInfo() {
int raumNummer = 101; // Lokale Variable: nur in PrintInfo sichtbar if (raumNummer > 100) {
int tischNummer = 5; // Nur in diesem if-Block sichtbar Console.WriteLine(tischNummer);
} Console.WriteLine(tischNummer); // Fehler! tischNummer ist hier nicht mehr sichtbar
}
}

2. Lokale Funktionen und Scope

Wer sieht wen?

Wenn du eine lokale Funktion innerhalb einer Methode (oder sogar in einer Schleife oder Bedingung) deklarierst, ist sie im selben Scope wie die Variablen, die weiter oben deklariert wurden. Die lokale Funktion ist quasi "Teil dieses Zimmers".

Beispiel

Die lokale Funktion sieht Variablen aus dem umgebenden Scope


    void PrintWithPrefix(string nachricht)
{
    
  
string praefix = "[LOG]: "; void Print() {
Console.WriteLine( praefix + nachricht); // sieht beide Variablen!
} Print();
}

Hier sind die Variablen praefix und nachricht innerhalb der lokalen Funktion Print sichtbar, weil sie im selben oder in einem weiteren Scope deklariert wurden.

Wie viele Scopes gibt's hier?

Im Beispiel oben:

  • gibt es den Scope der Methode PrintWithPrefix
  • und darin den Scope der Funktion Print
Lokale Funktionen machen keinen komplett eigenen "Raum" auf: Sie können alles sehen, was im Flur (der Methode) ist.

3. Variable Capture (Capture)

Variable Capture ist der Fall, wenn eine lokale Funktion Variablen benutzt, die außerhalb dieser Funktion, aber im selben Scope deklariert wurden.

Lokale Funktionen und anonyme Methoden (Lambda-Ausdrücke, dazu kommen wir noch) merken sich (oder "capturen") alle Variablen, die beim Deklarieren sichtbar waren.

Man kann sagen, die Funktionen machen einen Snapshot (capture) der Umgebung – und können diese Variablen auch dann noch benutzen, wenn sie viel später aufgerufen werden.

Schematisch

Methode Main
└─ Variable x
└─ lokale Funktion F() ← "captured" x

Beispiel – einfaches Capture

void CounterBeispiel()
{
    int zaehler = 0;

    void Erhoehen()
    {
        zaehler++; // Diese Funktion captured die Variable zaehler
    }

    Erhoehen();
    Erhoehen();
    Console.WriteLine(zaehler); // Gibt 2 aus
}
Die lokale Funktion captured eine Variable aus dem äußeren Scope

Hier wird nach zwei Aufrufen der lokalen Funktion Erhoehen der Wert von zaehler auf 2 erhöht.

4. Anwendung von Variable Capture

Variable Capture macht es easy, Daten zwischen dem Methodenscope und lokalen Funktionen zu "übergeben", ohne sich mit unnötigen Parametern rumzuärgern.

Ohne Capture müsstest du alle Variablen als Parameter übergeben:

void CounterBeispielOhneCapture()
{
    int zaehler = 0;

    void Erhoehen(ref int c)
    {
        c++;
    }

    Erhoehen(ref zaehler);
    Erhoehen(ref zaehler);
    Console.WriteLine(zaehler);
}

Das ist nervig – warum ständig ref schreiben und die Funktionssignatur verhunzen, wenn die Funktion die Variablen draußen easy sehen kann?

5. Lokale Funktionen und das Leben der Variablen nach dem Methodenende

Leben Variablen länger als die Methode?

Wenn du eine lokale Funktion (oder einen Delegate mit Lambda) irgendwo außerhalb der aktuellen Methode weitergibst, sterben die gecaptureden Variablen nicht automatisch beim Methodenende. Die CLR (die .NET-VM) kümmert sich drum – alles Nötige bleibt im Speicher "am Leben".

Beispiel: Funktionen leben außerhalb der Methode

Func<int> GetCounter()
{
    int zaehlen = 0;
    int Erhoehen()
    {
        zaehlen++;
        return zaehlen;
    }
    return Erhoehen; // Wir geben die Funktion nach draußen zurück!
}

var counter = GetCounter();
Console.WriteLine(counter()); // 1
Console.WriteLine(counter()); // 2
Closure: Die Variable zaehlen lebt nach dem Methodenende weiter

Hier lebt die Variable zaehlen auch nach dem Ende der Methode GetCounter weiter, weil die zurückgegebene Funktion sie gecaptured hat. Das nennt man Closure – dazu gibt's noch eine eigene Vorlesung, aber bei lokalen Funktionen läuft das genauso.

6. Typische Fehler und interessante Szenarien

Variable überschreiben vor dem Aufruf der lokalen Funktion

Manchmal passiert es, dass die Variable, die von der lokalen Funktion gecaptured wird, vor deren Aufruf geändert wird – und dann kommt ein anderes Ergebnis raus als erwartet.

Beispiel:


void Beispiel()
{
    int x = 42;
    void PrintX() {  Console.WriteLine(x);  } 

    x = 100; // Variable geändert!
    PrintX(); // Gibt 100 aus, nicht 42!
}

Trick: Die lokale Funktion sieht immer den aktuellsten Wert der Variable zum Zeitpunkt des Aufrufs.

Variable Capture in for/foreach-Schleifen (nochmal)

Klassischer Pain: Wenn du Logik im Bewerbungsgespräch oder in einem großen Projekt schreibst, check immer: Capture ich hier eine "lebende" Variable aus der Schleife, und wie verhält sie sich?

2
Aufgabe
C# SELF, Level 11, Lektion 5
Gesperrt
Einfache Verwendung einer lokalen Funktion und das Erfassen von Variablen
Einfache Verwendung einer lokalen Funktion und das Erfassen von Variablen
2
Aufgabe
C# SELF, Level 11, Lektion 5
Gesperrt
Initialisierung eines Zahlenzählers mit einer lokalen Funktion
Initialisierung eines Zahlenzählers mit einer lokalen Funktion
1
Umfrage/Quiz
Tuples und lokale Funktionen, Level 11, Lektion 5
Nicht verfügbar
Tuples und lokale Funktionen
Vorteile von Tuples gegenüber out und anonymen Typen
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION