로컬 함수

도우미 논리에 설명이 포함된 이름을 지정하려는 경우 그리고 해당 도우미가 필요한 멤버가 하나뿐인 경우 로컬 함수를 선택합니다. 포함하는 형식의 메서드와 비교할 때 로컬 함수는 도우미가 이 작업에 속한다는 것을 독자에게 알려줍니다. 해당 이름을 통해 독자는 세부 정보를 살펴보기 전에 기본 흐름을 따를 수 있습니다.

Tip

이 문서에서는 메서드를 작성하는 방법을 알고 있는 개발자를 위해 로컬 함수를 실제로 사용하는 방법을 설명합니다. 선언 세부 정보 및 진단 규칙은 로컬 함수 선언을 참조하세요.

로컬 함수는 메서드 또는 생성자와 같은 다른 멤버 내에 선언된 명명된 함수입니다. 해당 이름은 해당 멤버 내에서만 유효합니다.

다음 구문 형식은 로컬 함수를 선언하고 호출합니다.

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

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

AddGreeting은 CreateMessage 내부에 있습니다. 형식의 다른 멤버는 이를 호출할 수 없습니다.

헬퍼 로직은 이를 호출하는 코드 가까이에 두세요

로컬 함수를 사용하면 도우미 함수가 개별 단계를 설명하는 동안 주 흐름이 무엇이 일어나는지 나타내게 합니다. 다음 예제에서는 읽기 계획을 만듭니다. 로컬 함수를 사용하여 한 번에 1주일의 할당을 추가합니다.

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

ReadingWeek는 주 번호와 해당 주에 할당된 장 범위를 기록합니다. AddWeek는 CreateReadingPlan에만 속하므로 해당 로컬 범위는 그 관계를 전달합니다.

로컬 함수는 로컬 함수를 호출하는 문 앞이나 뒤에 선언할 수 있습니다. 독자가 컨텍스트를 잃지 않고 기본 흐름을 따를 수 있는 위치에 배치합니다.

매개 변수 사용 또는 로컬 상태 캡처

비정적 로컬 함수는 해당 함수를 포함하는 멤버의 매개 변수 및 지역 변수를 사용할 수 있습니다. 이 사용을 캡처라고합니다. 읽기 계획 예에서는 AddWeek는 다음을 캡처합니다:

  • CreateReadingPlan 매개 변수의 bookTitle, chapterCount 및 chaptersPerWeek
  • plan 지역 변수에서.

캡처는 도우미가 주변 작업에 자연스럽게 속하는 경우에 유용합니다. 캡처하는 값은 최소한으로 하고 명확하게 하세요 도우미가 매개 변수를 통해 모든 데이터를 수신할 수 있는 경우 static로컬 함수를 고려하세요.

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

정적 로컬 함수는 포함하는 멤버에서 지역 변수, 매개 변수 또는 인스턴스 상태를 캡처할 수 없습니다. 해당 매개 변수는 제공된 데이터를 명시적으로 만드는 반면 캡처를 통해 도우미는 도우미를 포함하는 작업의 컨텍스트를 사용할 수 있습니다.

문제가 반복될 때는 재귀를 사용하세요

재귀는 함수가 문제의 작은 부분으로 자신을 호출할 때 발생합니다. AddWeek 예제에서 1주일을 추가한 다음, 다음 주의 첫 번째 챕터를 사용하여 자신을 호출합니다.

모든 재귀 함수에는 호출을 중지하는 조건이 필요합니다. firstChapter이 chapterCount를 초과하면 AddWeek이 중지됩니다:

if (firstChapter > chapterCount)
{
    return;
}

로컬 함수는 이름이 포함하는 멤버 전체에서 범위에 있으므로 재귀에 적합합니다. 반복된 작업을 더 직접적으로 표현할 때 루프를 선호합니다. 재귀 구조로 알고리즘을 더 쉽게 이해할 수 있는 경우 재귀를 선택합니다.

로컬 함수 또는 람다 식 선택

로컬 함수와 람다 식은 둘 다 주변 변수를 사용할 수 있지만 서로 다른 의도를 전달합니다.

선택 When
로컬 함수 도우미는 이름이 있거나, 여러 구문이 있거나, 재귀가 필요하거나, 포함하는 멤버 내 둘 이상의 위치에서 호출됩니다.
람다 식 짧은 동작 코드를 다른 메서드에 직접 전달하거나 대리자 변수에 저장합니다.

다음 코드는 두 가지 형식을 모두 사용합니다.

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는 Where에 전달된 규칙에 설명적인 이름을 지정합니다. Select에 전달된 람다는 사용 시점에서 짧은 변환을 수행합니다. 두 형태 모두 여기서 다른 메서드에 동작을 제공합니다. 로컬 함수는 읽기 계획 예제에서의 AddWeek처럼 직접 호출할 수 있는 도우미가 될 수도 있습니다.

여러 멤버가 해당 도우미를 필요로 하는 경우 로컬 함수 대신 일반 메서드를 사용합니다. 동작이 짧고 해당 용도가 수신 메서드에서 명확한 경우 대신 람다를 사용합니다.

로컬 함수는 yield return를 포함하는 반복기 함수일 수도 있습니다. 해당 용도는 Iterators 문서를 참조하세요.

또한, 다음을 참조하세요.