Статические локальные функции
Предотвращайте захват переменных ради ясности и производительности.
«Статические локальные функции» — бесплатный урок C# Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.
Статические локальные функции
Пометка локальной функции как static запрещает ей захватывать любые переменные из внешнего контекста или this. Это делает функцию самодостаточной и понятной, а также устраняет скрытые выделения памяти под замыкание.
Объявление статической локальной функции
Добавьте модификатор static перед возвращаемым типом. Функция по-прежнему может принимать параметры и возвращать значения, но не может обращаться к внешним локальным переменным.
using System;
public class Program
{
public static void Main()
{
static int Square(int n) => n * n; // captures nothing
Console.WriteLine(Square(6));
}
}Захват запрещён
Статическая локальная функция не может использовать локальные переменные из внешнего контекста. Всё необходимое нужно передать ей в параметрах, поэтому её входные данные становятся явными.
using System;
public class Program
{
public static void Main()
{
int factor = 3;
// factor must be passed in, not captured
static int Scale(int n, int f) => n * f;
Console.WriteLine(Scale(5, factor));
}
}Избежание скрытых выделений памяти
Нестатические локальные функции, захватывающие переменные, могут выделять скрытый объект замыкания. Статическая локальная функция никогда ничего не захватывает и полностью избегает такого выделения памяти.
using System;
public class Program
{
public static void Main()
{
// Pure helper, no closure object created
static bool IsEven(int n) => n % 2 == 0;
for (int i = 0; i < 5; i++)
Console.WriteLine(i + ": " + IsEven(i));
}
}Самодокументируемое намерение
Ключевое слово static сообщает читателям, что вспомогательная функция зависит только от своих аргументов. Эта гарантия упрощает анализ и тестирование функции.
using System;
public class Program
{
public static void Main()
{
static int Clamp(int value, int lo, int hi)
=> value < lo ? lo : value > hi ? hi : value;
Console.WriteLine(Clamp(15, 0, 10));
Console.WriteLine(Clamp(-3, 0, 10));
}
}Компилятор запрещает захват
Если вы случайно обратитесь к локальной переменной из внешнего контекста внутри статической локальной функции, компилятор сообщит об ошибке. Это помогает рано обнаружить непреднамеренные зависимости.
using System;
public class Program
{
public static void Main()
{
int seed = 7;
// Correct: seed is passed explicitly, not captured
static int Mix(int x, int s) => x * 31 + s;
Console.WriteLine(Mix(2, seed));
}
}Статические локальные функции с рекурсией
Статические локальные функции по-прежнему поддерживают рекурсию, поскольку вызов самой себя не равнозначен захвату переменной.
using System;
public class Program
{
public static void Main()
{
static int Power(int baseN, int exp)
=> exp == 0 ? 1 : baseN * Power(baseN, exp - 1);
Console.WriteLine(Power(2, 10));
}
}Сочетание с параметрами out
Как и любой метод, статическая локальная функция может использовать параметры out. Это хорошо сочетается с отсутствием захвата в чистых вспомогательных функциях в стиле TryParse.
using System;
public class Program
{
public static void Main()
{
static bool TryParsePositive(string s, out int value)
{
value = 0;
return int.TryParse(s, out value) && value > 0;
}
if (TryParsePositive("42", out int n))
Console.WriteLine("got " + n);
Console.WriteLine(TryParsePositive("-1", out _));
}
}Передача статических локальных функций как делегатов
Поскольку они ничего не захватывают, статические локальные функции преобразуются в делегаты без выделения замыкания, что может иметь значение на критических участках кода.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
static bool IsBig(int n) => n > 100;
var nums = new List<int> { 50, 150, 200, 10 };
Console.WriteLine(nums.Count(IsBig));
}
}Когда предпочитать static
Предпочитайте статическую локальную функцию, если вспомогательной функции не требуется состояние из внешнего контекста. Это документирует чистоту функции, предотвращает случайный захват и может повысить эффективность. Убирайте static только тогда, когда действительно нужно замкнуть локальные переменные.
using System;
public class Program
{
public static void Main()
{
static string Describe(int score)
{
if (score >= 90) return "A";
if (score >= 80) return "B";
return "C";
}
Console.WriteLine(Describe(95));
Console.WriteLine(Describe(82));
}
}Попробуйте сами
Напишите чистую статическую локальную функцию и передайте её в LINQ как предикат. Поскольку она ничего не захватывает, она преобразуется в делегат без замыкания.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
static bool IsLeapYear(int year)
=> (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
var years = new List<int> { 1900, 2000, 2004, 2021, 2024 };
Console.WriteLine(string.Join(", ", years.Where(IsLeapYear)));
}
}Быстрая проверка
Вспомните, что добавляет static локальной функции.
Повторение
Статическая локальная функция static ничего не захватывает.
- Она не может использовать локальные переменные из внешнего контекста или
this; передавайте данные через параметры. - Она избегает скрытых выделений памяти под замыкание.
- Компилятор принудительно соблюдает запрет на захват и обнаруживает случайные зависимости.
- Предпочитайте её всегда, когда вспомогательной функции не требуется состояние из внешнего контекста.
Часто задаваемые вопросы
Урок «Статические локальные функции» бесплатный?
Да — полный текст урока «Статические локальные функции» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.
Чему я научусь в уроке «Статические локальные функции»?
Предотвращайте захват переменных ради ясности и производительности. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C# Academy?
Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Статические локальные функции»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C# Academy?
Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Объявление локальных функций
- Замыкания и захваченные переменные
- Статические локальные функции
- Локальные функции и лямбда-выражения