Локальная функция в C# — это метод, определенный внутри другого метода. В некоторых случаях, локальные функции позволяют сделать код приложения более понятным и лаконичным.
Пример локальной функции
Как мы уже знаем, методы позволяют выделить участки кода в отдельные блоки и, в дальнейшем, многократно использовать этот код путем вызова соответствующего метода. Допустим, мы хотим сделать наше консольное приложение красивым — визуально выделять запрос приложения на ввод данных и вывод в консоль результатов вычислений. У нас уже есть готовый метод, который выводит разноцветный текст в консоль. Пусть наше приложение будет складывать два числа. Используя наш метод, мы можем написать вот такой код программы:
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { //запрос на получение данных от пользователя WriteColorText("Введите первое целое число:", ConsoleColor.Blue); int number_1 = int.Parse(Console.ReadLine()); WriteColorText("Введите второе целое число:", ConsoleColor.Blue); int number_2 = int.Parse(Console.ReadLine()); //вывод результата WriteColorText ($"Результат вычислений: {number_1 + number_2}", ConsoleColor.Green); } static void WriteColorText(string text, ConsoleColor color) { ConsoleColor oldColor = Console.ForegroundColor; //запоминаем текущий цвет текста Console.ForegroundColor = color; //меняем цвет на тот, который задан в параметрах Console.WriteLine(text); //выводим текст Console.ForegroundColor = oldColor; //возвращаем старый цвет } } }
здесь мы используем синий цвет текста для запроса данных, белый — для ввода значения, зеленый — для вывода результата. Что произойдет, если пользователь решит «пошутить» и задаст не целое число, а строку? Очевидно, что мы получим вот такой некрасивый вывод в консоль:
а сама программа аварийно завершится. Здесь было бы логично заставить пользователя вводить именно целые числа. Чтобы это сделать мы можем создать локальную функцию, которая будет обрабатывать ввод пользователя до тех пор, пока не будет получен необходимый результат. Перепишем код метода Main()
следующим образом:
static void Main(string[] args) { static int GetNumber() { int number; while (int.TryParse(Console.ReadLine(), out number) == false) { WriteColorText("Вводите только целые числа!", ConsoleColor.Red); } return number; } //запрос на получение данных от пользователя WriteColorText("Введите первое целое число:", ConsoleColor.Blue); int number_1 = GetNumber(); WriteColorText("Введите второе целое число:", ConsoleColor.Blue); int number_2 = GetNumber(); //вывод результата WriteColorText ($"Результат вычислений: {number_1 + number_2}", ConsoleColor.Green); }
Рассмотрим, что здесь изменилось. Во-первых, мы определили локальную функцию GetNumber()
:

Как можно видеть по рисунку, GetNumber()
располагается внутри тела метода Main()
и, следовательно, это уже не просто метод, а локальная функция, которая может использоваться только внутри Main()
, что мы собственно и делаем:

Внутри самой функции мы запускаем цикл, который будет продолжаться до тех пор, пока пользователь не введет целое число. Внутри цикла содержится всего одна инструкция — вывод сообщения об ошибке с использованием текста красного цвета. Если же пользователь с первого раза введет целое число, то сообщение об ошибке не появится (условие цикла окажется ложным), а наружу (в метод Main()
вернется заданное пользователем число.
Результат работы программы теперь будет таким:
Локальные функции могут вызывать другие локальные функции, если они расположены в одном методе.
Статические локальные функции
Кроме того, что локальные функции могут вызывать другие локальные функции, также локальные функции могут содержать другие локальные функции. То есть вложенность блоков кода может быть ещё больше. Сами локальные функции могут определяться с ключевым словом static
, то есть быть статическими. Такие функции не могут обращаться к переменным своего окружения, то есть к таким переменным, которые определены в том же методе, что и локальная функция. Например, сейчас наша функция GetNumber()
определена как статическая. Попробуем получить внутри этой функции какое-нибудь значение, определенное в методе Main():
{ ConsoleColor errorColor = ConsoleColor.Red; //переменная в методе Main() static int GetNumber() { int number; while (int.TryParse(Console.ReadLine(), out number) == false) { WriteColorText("Вводите только целые числа!", errorColor);//пробуем получить значение переменной } return number; } //запрос на получение данных от пользователя WriteColorText("Введите первое целое число:", ConsoleColor.Blue); int number_1 = GetNumber(); WriteColorText("Введите второе целое число:", ConsoleColor.Blue); int number_2 = GetNumber(); //вывод результата WriteColorText ($"Результат вычислений: {number_1 + number_2}", ConsoleColor.Green); }
При попытке получить значение переменной errorColor
внутри статической локальной функции Visual Studio стразу же укажет на ошибку:
Итого
Локальные функции — это методы, которые могут располагаться внутри других методов. Локальные функции удобно использовать в том случае, если какой-то метод содержит повторяющиеся участки кода и мы точно можем быть уверены в том, что эти участки кода не будут востребованы в других частях приложения — в этом случае их можно выделить в локальную функцию. Локальные функции используют переменные своего окружения (определенные в том же методе, в котором содержится локальная функция). При этом, статические локальные функции не имеют доступа к переменным своего окружения.