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

Локальные функции

C# SELF
11 уровень , 4 лекция
Открыта

1. Введение

Любой программист знает: функции (или методы) — это по сути "рабочие лошадки" любого приложения. Они помогают нам структурировать код, повторно использовать логику и не утонуть в бесконечных копипастах. До сих пор все функции, с которыми вы работали, были "соседями" в теле класса или структуры.

Но представьте, что у вас есть большая функция с куском не очень крупной логики, которую хочется как-то аккуратно вынести, не показывая её всему проекту. Например, вспомогательный расчёт внутри метода, который больше нигде не нужен.

В таком случае на помощь приходят локальные функции.

Локальная функция — это функция, объявленная внутри другой функции (метода, конструктора, свойства или даже другой локальной функции). И такая локальная функция видна только "родителю" и нигде больше.

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


void MainMethod()
{
    Console.WriteLine("Starting the main method.");            // Начало работы основного метода.
    int result = InnerSum(5, 7);                              // Вызов локальной функции InnerSum (внутренняя сумма)
    Console.WriteLine($"Local function result: {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("Нет оценок для расчёта."); // No scores to calculate.
        return;
    }

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

    // Локальная функция для вычисления средней
    
  
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("Это чётное число, поздравляем!"); }
} }

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

Локальная функция vs обычный приватный метод

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

5. Типичные ошибки и особенности реализации

Ошибка №1: опечатка или пропуск объявления локальной функции.
Если вы вызываете локальную функцию с неверным именем или забываете её объявить, компилятор сообщит об ошибке CS0103 или CS0128, и код не скомпилируется.

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

Ошибка №3: игнорирование подсказок IDE по преобразованию приватных методов.
Если вы оставляете в классе ненужные приватные методы, хотя IDE (например, Rider) предлагает сделать их локальными функциями, в коде быстро накапливается «мусор» и ухудшается читаемость.

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

2
Задача
C# SELF, 11 уровень, 4 лекция
Недоступна
Использование локальной функции для вычисления суммы двух чисел
Использование локальной функции для вычисления суммы двух чисел
2
Задача
C# SELF, 11 уровень, 4 лекция
Недоступна
Локальная функция для проверки чётности числа
Локальная функция для проверки чётности числа
Комментарии (2)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Slevin Уровень 56
27 января 2026
Сломан формат отображения кода во всей лекции.
Станислав Уровень 16
30 октября 2025
Добавить пробел после двоеточия в приглашениях, чтобы точьнее соответствовать примеру: "Введите первое число: 10" и "Введите второе число: 20". Сейчас вывод без пробела перед вводом числа. Спасибо! Спасибо что так докапываетесь до вывода!