Lokala funktioner

Välj en lokal funktion när du vill ge hjälplogik ett beskrivande namn och bara en medlem behöver hjälpfunktionen. Jämfört med en metod för den omslutande typen meddelar en lokal funktion läsarna att hjälpfunktionen tillhör den här åtgärden. Med dess namn kan läsarna följa huvudflödet innan de inspekterar detaljerna.

Tip

Den här artikeln lär dig praktisk användning av lokala funktioner för utvecklare som vet hur man skriver metoder. Information om deklaration och diagnostikregler finns i Lokala funktionsdeklarationer.

En lokal funktion är en namngiven funktion som deklareras inuti en annan medlem, till exempel en metod eller konstruktor. Namnet gäller endast för den medlemmen.

Följande form deklarerar och anropar en lokal funktion:

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

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

AddGreeting förblir inuti CreateMessage. Andra medlemmar av typen kan inte anropa den.

Håll hjälplogik nära anroparen

Med lokala funktioner kan huvudflödet avgöra vad som händer medan hjälpfunktionerna förklarar enskilda steg. Följande exempel skapar en läsplan. Den använder en lokal funktion för att lägga till en veckas tilldelning i taget.

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);
    }
}

En ReadingWeek registrerar ett veckonummer och det intervall med kapitel som tilldelats för den veckan. AddWeek tillhör endast CreateReadingPlan, så dess lokala synlighet kommunicerar den relationen.

Du kan deklarera en lokal funktion före eller efter de instruktioner som anropar den. Placera den där läsarna kan följa huvudflödet utan att förlora kontexten.

Använd parametrar eller fånga lokalt tillstånd

En icke-statisk lokal funktion kan använda parametrar och lokala variabler från dess innehållande medlem. Den här användningen kallas insamling. I exemplet AddWeek med läsplanen fångas:

  • bookTitle, chapterCount och chaptersPerWeek från parametrarna i CreateReadingPlan.
  • plan från en lokal variabel.

Insamling är användbart när hjälpen naturligt tillhör den omgivande åtgärden. Håll antalet insamlade värden nere och gör dem tydliga. Om hjälpmetoden kan ta emot alla sina data via parametrar bör du överväga en static lokal funktion:

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

En statisk lokal funktion kan inte fånga lokala variabler, parametrar eller instanstillstånd från den innehållande medlemmen. Dess parametrar gör de angivna data explicita, medan capture låter en hjälpare använda kontexten för dess innehållande åtgärd.

Använd rekursion när problemet upprepar sig

Rekursion uppstår när en funktion anropar sig själv med en mindre del av problemet. AddWeek i exemplet lägger till en vecka och anropar sedan sig själv med det första kapitlet för nästa vecka.

Varje rekursiv funktion behöver ett villkor som stoppar anropen. AddWeek stoppar när firstChapter överskrider chapterCount:

if (firstChapter > chapterCount)
{
    return;
}

Lokala funktioner fungerar bra för rekursion eftersom deras namn är synliga i hela den omgivande medlemmen. Välj en loop när den uttrycker det upprepade arbetet mer direkt. Välj rekursion när rekursiv struktur gör algoritmen enklare att förstå.

Välj en lokal funktion eller lambda-uttryck

Lokala funktioner och lambda-uttryck kan båda använda omgivande variabler, men de kommunicerar olika avsikter:

Välj När
Lokal funktion Hjälpfunktionen drar nytta av ett namn, har flera satser, behöver rekursion eller anropas från mer än en plats i den innehållande medlemmen.
Lambda-uttryck Du skickar ett kort kodblock direkt till en annan metod eller lagrar det i en delegatvariabel.

Följande kod använder båda formerna:

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 ger regeln som skickas till Where ett beskrivande namn. Lambda som skickas till Select utför en kort omvandling vid dess användningspunkt. Båda formerna ger en annan metod ett beteende här. En lokal funktion kan också vara en hjälp som du anropar direkt, precis som AddWeek i exemplet med läsplanen.

Använd en vanlig metod i stället för en lokal funktion när flera medlemmar behöver hjälpmetoden. Använd en lambda i stället när beteendet är kort och dess syfte är tydligt från metoden som tar emot den.

Lokala funktioner kan också vara iteratorfunktioner som innehåller yield return. För den användningen, se Iteratorer.

Se även