JavaRush /Курси /C# SELF /Локальні функції

Локальні функції

C# SELF
Рівень 11 , Лекція 4
Відкрита

1. Вступ

Будь-який програміст знає: функції (або методи) — це, по суті, «робочі конячки» будь-якого застосунку. Вони допомагають нам структурувати код, повторно використовувати логіку і не потонути в нескінченному копіюванні коду. Досі всі функції, з якими ви працювали, були «сусідами» у тілі класу або структури.

Але уявіть, що у вас є велика функція з невеликим фрагментом логіки, яку хочеться акуратно винести, не роблячи її видимою для всього проєкту. Наприклад, допоміжний розрахунок всередині методу, який більше ніде не потрібен.

У такому разі на допомогу приходять локальні функції.

Локальна функція — це функція, оголошена всередині іншої функції (методу, конструктора, властивості або навіть іншої локальної функції). Вона доступна лише в «батьківській» функції — і ніде більше.

Синтаксис локальних функцій


void MainMethod()
{
    Console.WriteLine("Початок роботи основного методу.");            // Початок роботи основного методу.
    int result = InnerSum(5, 7);                              // Виклик локальної функції InnerSum (внутрішня сума)
    Console.WriteLine($"Результат локальної функції: {result}");    // Результат локальної функції: {result}

    // Локальна функція оголошується безпосередньо всередині MainMethod
    
  
int InnerSum(int a, int b) // Локальна функція для додавання двох чисел { return a + b; // Повертає суму a й b }
}

У цьому прикладі функція InnerSum оголошена безпосередньо всередині методу MainMethod. Вона недоступна за межами основного методу — жодним чином. Подібно до секретної інструкції, якою можна поділитися лише наодинці.

2. Як оголошувати і де використовувати локальні функції

Базові правила

  • Локальну функцію можна оголошувати всередині: методу, конструктора, властивості, оператора або навіть іншої локальної функції!
  • Локальна функція видима лише в межах власної області видимості (scope).
  • Локальні функції можна викликати до або після їх оголошення в батьківській функції (C# усе аналізує заздалегідь).

Приклад: розрахунок середньої оцінки


// Основна функція для виведення середньої оцінки
void PrintAverageScore(int[] scores)
{
    if (scores.Length == 0)
    {
        Console.WriteLine("Немає оцінок для розрахунку."); // Немає оцінок для розрахунку.
        return;
    }

    double average = CalculateAverage(scores);
    Console.WriteLine($"Середня оцінка: {average:0.00}"); // Середня оцінка

    // Локальна функція для обчислення середнього
    
  
double CalculateAverage(int[] arr) { int sum = 0; foreach (var score in arr) sum += score; return (double)sum / arr.Length; // Повертає середнє }
} // Виклик функції: int[] myScores = { 5, 4, 3, 4, 5 }; PrintAverageScore(myScores); // Виведе: Середня оцінка: 4.20

Бачите, як зручно? Ніхто за межами PrintAverageScore не може скористатися її внутрішньою логікою — локальною функцією CalculateAverage. Такий підхід допомагає тримати код упорядкованим і не засмічувати глобальний простір імен допоміжними методами.

3. Локальні функції та область видимості (scope)

Головна особливість локальної функції — її область видимості обмежена «батьківським» методом. Така поведінка запобігає «засміченню» класу дрібними методами, які використовуються тільки в одному місці.


+-----------------+
|   Метод класу   |
|    void Foo()   |
|                 |
|   +-----------+ |
|   | Локальна  | |
|   | функція   | |
|   +-----------+ |
+-----------------+
Локальна функція існує тільки всередині методу, де оголошена

Локальна функція існує тільки всередині методу, де оголошена. Спроба звернутися до неї ззовні рівнозначна спробі зателефонувати на секретну лінію, якої у вас немає.

Якщо ви випадково викличете локальну функцію поза батьківським методом, отримаєте помилку компіляції: Імʼя '...' не існує в поточному контексті.

Локальні функції «бачать» змінні батьківського методу

Локальні функції можуть звертатися до всіх змінних батьківського методу — у цьому їхня суперсила!


void ShowStudent(string name, int age)
{
    string message = BuildMessage();
    Console.WriteLine(message);

    // Локальна функція використовує змінні "name" і "age"
    
  
string BuildMessage() { return $"Імʼя: { name}, Вік: { age}"; }
}

Це робить код не тільки коротшим, а й набагато менш «шумним». Не треба передавати десять параметрів у кожен метод — локальна функція «бачить» усе, що є у батьківському методі.

4. Локальні функції всередині циклів і умов

Локальні функції можна оголошувати на будь-якому рівні вкладеності — навіть усередині циклів або гілок умов:


void ProcessNumbers(int[] numbers)
{
    foreach (int number in numbers)
    {
        if (number % 2 == 0)
        {
            Console.WriteLine($"{number} — парне");
            PrintEvenMessage();
        }
        else
        {
            Console.WriteLine($"{number} — непарне");
        }

        
  
void PrintEvenMessage() { Console.WriteLine("Це парне число, вітаємо!"); }
} }

Але такий підхід може швидко зробити код менш читабельним, особливо якщо локальних функцій стає забагато або вони довгі. Зловживати не варто, але знати про таку можливість корисно.

Локальна функція проти звичайного приватного методу

Критерій Локальна функція Приватний метод класу
Область видимості Тільки батьківська функція Весь клас
Доступ до змінних батьківського методу Так Ні (лише через параметри)
Спрощення читабельності Високе Середнє
Потенціал повторного використання Низький Високий
Тестованість Складно тестувати Легко тестувати

5. Типові помилки та особливості реалізації

Помилка № 1: описка або пропуск оголошення локальної функції.
Якщо ви викликаєте локальну функцію з неправильним іменем або забуваєте її оголосити, компілятор повідомить про помилку CS0103 або CS0128, і код не скомпілюється.

Помилка № 2: зміна захоплених змінних (замикання, closure).
Коли локальна функція змінює значення змінної із зовнішнього методу, ви можете отримати зовсім не той результат, який очікували — захоплені змінні поводяться як копії або посилання, і їхня зміна впливає на логіку.

Помилка № 3: ігнорування підказок IDE щодо перетворення приватних методів.
Якщо ви залишаєте у класі непотрібні приватні методи, хоча IDE (наприклад, Rider) пропонує зробити їх локальними функціями, у коді швидко накопичується «сміття» і погіршується читабельність.

Помилка № 4: надмірна глибина вкладеності локальних функцій.
Забагато рівнів вкладених функцій ускладнюють розуміння й налагодження коду. Лаконічність — ключ до зручного супроводу.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ