static int AddWrapper(int x, int y)
{
// Здесь должна выполняться какая-то проверка достоверности.
return Add();
int Add()
{
return x + y;
}
}
Содержащийся в AddWrapper()
метод Add()
можно вызывать лишь из объемлющего метода AddWrapper()
. Почти наверняка вас интересует, что это вам дало? В приведенном примере мало что (если вообще что-либо). Но если функцию Add()
нужно вызывать во многих местах метода AddWrapper()
? И вот теперь вы должны осознать, что наличие локальной функции, не видимой за пределами того места, где она необходима, содействует повторному использованию кода. Вы увидите еще больше преимуществ, обеспечиваемых локальными функциями, когда мы будем рассматривать специальные итераторные методы (в главе 8) и асинхронные методы (в главе 15).
На заметку!AddWrapper()
является примером локальной функции с вложенной локальной функцией. Вспомните, что функции, объявляемые в операторах верхнего уровня, создаются как локальные функции. Локальная функция Add()
находится внутри локальной функции AddWrapper()
. Такая возможность обычно не применяется за рамками учебных примеров, но если вам когда-нибудь понадобятся вложенные локальные функции, то вы знаете, что они поддерживаются в С#.
В версии C# 9.0 локальные функции обновлены, чтобы позволить добавлять атрибуты к самой локальной функции, ее параметрам и параметрам типов, как показано далее в примере (не беспокойтесь об атрибуте NotNullWhen
, который будет раскрыт позже в главе):
#nullable enable
private static void Process(string?[] lines, string mark)
{
foreach (var line in lines)
{
if (IsValid(line))
{
// Логика обработки. ..
}
}
bool IsValid([NotNullWhen(true)] string? line)
{
return !string.IsNullOrEmpty(line) && line.Length >= mark.Length;
}
}
Статические локальные функции (нововведение в версии 8.0)
В версии C# 8 средство локальных функций было усовершенствовано — появилась возможность объявлять локальную функцию как статическую. В предыдущем примере внутри локальной функции Add()
производилась прямая ссылка на переменные из главной функции. Результатом могут стать неожиданные побочные эффекты, поскольку локальная функция способна изменять значения этих переменных.
Чтобы увидеть возможные побочные эффекты в действии, создайте новый метод по имени AddWrapperWithSideEffeet()
с таким кодом:
static int AddWrapperWithSideEffect(int x, int y)
{
// Здесь должна выполняться какая-то проверка достоверности
return Add();
int Add()
{
x += 1;
return x + y;
}
}
Конечно, приведенный пример настолько прост, что вряд ли что-то подобное встретится в реальном коде. Для предотвращения ошибки подобного рода добавьте к локальной функции модификатор static
. Это не позволит локальной функции получать прямой доступ к переменным родительского метода, генерируя на этапе компиляции исключение CS8421, "A static local function cannot contain a reference to ‘<имя переменной>’" (Статическая локальная функция не может содержать ссылку на ‘<имя переменной>’).
Ниже показана усовершенствованная версия предыдущего метода:
static int AddWrapperWithStatic(int x, int y)
{
// Здесь должна выполняться какая-то проверка достоверности
return Add(x,y);
static int Add(int x, int y)
{
return x + y;
}
}
Понятие параметров методов
Параметры методов применяются для передачи данных вызову метода. В последующих разделах вы узнаете детали того, как методы (и вызывающий их код) обрабатывают параметры.
Модификаторы параметров для методов
Стандартный способ передачи параметра в функцию —
Хотя определение метода в C# выглядит достаточно понятно, с помощью модификаторов, описанных в табл. 4.2, можно управлять способом передачи аргументов методу.
Чтобы проиллюстрировать использование перечисленных ключевых слов, создайте новый проект консольного приложения по имени FunWithMethods
. А теперь давайте рассмотрим их роль.