Lokale Funktionen

Wählen Sie eine lokale Funktion aus, wenn Sie der Hilfslogik einen aussagekräftigen Namen geben möchten und nur ein Member diese Hilfsfunktion benötigt. Im Vergleich zu einer Methode im enthaltenden Typ teilt eine lokale Funktion Lesern mit, dass die Hilfsfunktion zu diesem Vorgang gehört. Mit seinem Namen können Leser den Hauptablauf verfolgen, bevor sie die Details überprüfen.

Tip

In diesem Artikel wird die praktische Verwendung lokaler Funktionen für Entwickler vermittelt, die wissen, wie man Methoden schreibt. Details zu Deklarationen und Diagnoseregeln finden Sie unter Lokale Funktionsdeklarationen.

Eine lokale Funktion ist eine benannte Funktion, die innerhalb eines anderen Members deklariert wird, z. B. eine Methode oder ein Konstruktor. Der Name befindet sich nur innerhalb dieses Members im Gültigkeitsbereich.

Das folgende Shape deklariert und ruft eine lokale Funktion auf:

string CreateMessage(string name)
{
    return AddGreeting(name);

    string AddGreeting(string value) => $"Hello, {value}!";
}

AddGreeting bleibt in CreateMessage. Andere Mitglieder des Typs können es nicht aufrufen.

Hilfslogik in der Nähe des Aufrufers beibehalten

Lokale Funktionen legen im Hauptablauf fest, was geschieht, während Hilfsfunktionen einzelne Schritte erläutern. Im folgenden Beispiel wird ein Leseplan erstellt. Sie verwendet eine lokale Funktion, um jeweils die Zuweisung für eine Woche hinzuzufügen.

IReadOnlyList<ReadingWeek> plan =
    CreateReadingPlan("The Long Way Home", chapterCount: 10, chaptersPerWeek: 3);

foreach (ReadingWeek week in plan)
{
    Console.WriteLine(
        $"Week {week.Number}: {week.BookTitle}, chapters {week.FirstChapter}-{week.LastChapter}");
}

static IReadOnlyList<ReadingWeek> CreateReadingPlan(
    string bookTitle,
    int chapterCount,
    int chaptersPerWeek)
{
    var plan = new List<ReadingWeek>();
    AddWeek(firstChapter: 1);
    return plan;

    void AddWeek(int firstChapter)
    {
        if (firstChapter > chapterCount)
        {
            return;
        }

        int lastChapter = Math.Min(
            firstChapter + chaptersPerWeek - 1,
            chapterCount);

        plan.Add(new ReadingWeek(
            plan.Count + 1,
            bookTitle,
            firstChapter,
            lastChapter));

        AddWeek(lastChapter + 1);
    }
}

Ein ReadingWeek erfasst eine Wochennummer und den Bereich der Kapitel, die für diese Woche zugewiesen sind. AddWeek gehört nur zu CreateReadingPlan, sodass sein lokaler Gültigkeitsbereich diese Beziehung kommuniziert.

Sie können eine lokale Funktion vor oder nach den Anweisungen deklarieren, die diese Funktion aufrufen. Platzieren Sie ihn, wo Leser dem Hauptfluss folgen können, ohne den Kontext zu verlieren.

Verwenden Sie Parameter oder erfassen Sie den lokalen Status

Eine nicht statische lokale Funktion kann Parameter und lokale Variablen aus dem enthaltenden Element verwenden. Diese Verwendung wird als Erfassung bezeichnet. Im Leseplanbeispiel AddWeek wird Folgendes erfasst:

  • bookTitle, chapterCountund chaptersPerWeek aus den CreateReadingPlan Parametern.
  • plan aus einer lokalen Variablen.

Capture ist nützlich, wenn der Helfer natürlich zum umgebenden Vorgang gehört. Halten Sie die Anzahl der erfassten Werte gering und übersichtlich. Wenn die Hilfsfunktion alle zugehörigen Daten über Parameter empfangen kann, sollten Sie eine static lokale Funktion in Betracht ziehen:

static int LastChapter(int firstChapter, int chaptersPerWeek, int chapterCount) =>
    Math.Min(firstChapter + chaptersPerWeek - 1, chapterCount);

Eine statische lokale Funktion kann keine lokalen Variablen, Parameter oder Instanzzustände aus dem enthaltenden Element erfassen. Seine Parameter machen die bereitgestellten Daten explizit, während Capture es einem Hilfsprogramm ermöglicht, den Kontext des enthaltenden Vorgangs zu verwenden.

Verwenden Sie Rekursion, wenn sich das Problem wiederholt

Rekursion tritt auf, wenn eine Funktion sich selbst mit einem kleineren Teil des Problems aufruft. AddWeek im Beispiel fügt eine Woche hinzu und ruft sich dann selbst mit dem ersten Kapitel für die nächste Woche auf.

Jede rekursive Funktion benötigt eine Bedingung, die die Aufrufe beendet. AddWeek stoppt, wenn firstChapterchapterCount überschreitet:

if (firstChapter > chapterCount)
{
    return;
}

Lokale Funktionen eignen sich gut für Rekursion, da ihre Namen im gesamten umgebenden Member gültig sind. Bevorzugen Sie eine Schleife, wenn sie die wiederholte Arbeit direkter ausdrücket. Wählen Sie Rekursion aus, wenn die rekursive Struktur den Algorithmus leichter verständlich macht.

Lokale Funktion oder Lambda-Ausdruck auswählen

Lokale Funktionen und Lambda-Ausdrücke können beide umgebende Variablen verwenden, aber sie kommunizieren unterschiedliche Absichten:

Auswählen Wenn
Lokale Funktion Die Hilfsmethode profitiert von einem Namen, hat mehrere Anweisungen, benötigt Rekursion oder wird von mehr als einer Stelle im enthaltenden Element aufgerufen.
Lambda-Ausdruck Sie übergeben kurzen Code direkt an eine andere Methode oder speichern ihn in einer Delegatvariable.

Der folgende Code verwendet beide Formen:

static IEnumerable<string> DescribeShortWeeks(
    IEnumerable<ReadingWeek> plan,
    int maximumChapters)
{
    return plan
        .Where(IsShortWeek)
        .Select(week => $"Week {week.Number}: {week.FirstChapter}-{week.LastChapter}");

    bool IsShortWeek(ReadingWeek week) =>
        week.LastChapter - week.FirstChapter + 1 <= maximumChapters;
}

Console.WriteLine("Short weeks:");
foreach (string description in DescribeShortWeeks(plan, maximumChapters: 2))
{
    Console.WriteLine(description);
}

IsShortWeek gibt der an Where übergebenen Regel einen beschreibenden Namen. Die an Select übergebene Lambda-Funktion führt an ihrem Verwendungspunkt eine kurze Transformation aus. Beide Formen stellen hier einer anderen Methode Verhalten bereit. Eine lokale Funktion kann auch eine Hilfsfunktion sein, die Sie direkt aufrufen, wie AddWeek im Beispiel zum Leseplan.

Verwenden Sie eine reguläre Methode anstelle einer lokalen Funktion, wenn mehrere Member die Hilfsfunktion benötigen. Verwenden Sie stattdessen eine Lambda-Funktion, wenn das Verhalten kurz ist und ihr Zweck aus der empfangenden Methode klar ist.

Lokale Funktionen können auch Iteratorfunktionen sein, die yield return enthalten. Für diese Verwendung siehe Iteratoren.

Siehe auch