0Pricing
C# Academy · Урок

Локальные функции и лямбда-выражения

Выбирайте между локальными функциями и лямбда-выражениями.

«Локальные функции и лямбда-выражения» — бесплатный урок C# Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Локальные функции и лямбда-выражения

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

Два способа написать вспомогательную функцию

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

using System;

public class Program
{
    public static void Main()
    {
        int SquareFn(int n) => n * n;       // local function
        Func<int, int> squareLambda = n => n * n; // lambda

        Console.WriteLine(SquareFn(4));
        Console.WriteLine(squareLambda(4));
    }
}

Локальные функции упрощают рекурсию

Локальная функция может вызывать себя по имени. Лямбда-выражение не может ссылаться на собственную переменную во время инициализации, поэтому рекурсия с лямбда-выражениями неудобна.

using System;

public class Program
{
    public static void Main()
    {
        // Clean recursion with a local function
        int Factorial(int n) => n <= 1 ? 1 : n * Factorial(n - 1);
        Console.WriteLine(Factorial(5));
    }
}

Локальные функции могут быть обобщёнными

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

using System;

public class Program
{
    public static void Main()
    {
        T First<T>(T[] items) => items[0]; // generic local function

        Console.WriteLine(First(new[] { 9, 8, 7 }));
        Console.WriteLine(First(new[] { "a", "b" }));
    }
}

Производительность: избежание выделения делегата

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

using System;

public class Program
{
    public static void Main()
    {
        // Direct call, no delegate or closure allocation
        static int Add(int a, int b) => a + b;

        int total = 0;
        for (int i = 0; i < 5; i++) total = Add(total, i);
        Console.WriteLine(total);
    }
}

Параметры out и ref

Локальные функции могут объявлять параметры out и ref, а лямбда-выражения через распространённые делегаты Func/Action — нет. Поэтому вспомогательные функции в стиле TryParse естественно реализовывать как локальные функции.

using System;

public class Program
{
    public static void Main()
    {
        bool TryGetFirstDigit(string s, out int digit)
        {
            digit = 0;
            foreach (var c in s)
                if (char.IsDigit(c)) { digit = c - '0'; return true; }
            return false;
        }

        if (TryGetFirstDigit("abc4", out int d))
            Console.WriteLine(d);
    }
}

Лямбды особенно удобны как непосредственные аргументы

Если нужно передать поведение прямо в метод, например LINQ Where или Select, лямбда будет самым кратким и понятным вариантом.

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 1, 2, 3, 4, 5, 6 };
        var evens = nums.Where(n => n % 2 == 0).Select(n => n * 10);
        Console.WriteLine(string.Join(", ", evens));
    }
}

Захват работает в обоих случаях

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

using System;

public class Program
{
    public static void Main()
    {
        int bonus = 10;
        int WithBonusFn(int n) => n + bonus;     // captures
        Func<int, int> withBonusLambda = n => n + bonus; // captures

        Console.WriteLine(WithBonusFn(5));
        Console.WriteLine(withBonusLambda(5));
    }
}

Определённое присваивание и порядок

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

using System;

public class Program
{
    public static void Main()
    {
        Console.WriteLine(Triple(4)); // allowed before declaration

        int Triple(int n) => n * 3;
    }
}

Как выбрать между ними

Используйте локальную функцию для именованных, повторно используемых, рекурсивных или обобщённых вспомогательных функций, а также для вспомогательных функций на часто выполняемом пути. Используйте лямбду для короткого поведения, передаваемого непосредственно в другой метод. Оба варианта — инструменты; выбирайте их исходя из цели.

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        static bool IsPrime(int n)
        {
            if (n < 2) return false;
            for (int i = 2; i * i <= n; i++)
                if (n % i == 0) return false;
            return true;
        }

        var primes = Enumerable.Range(2, 20).Where(IsPrime);
        Console.WriteLine(string.Join(", ", primes));
    }
}

Попробуйте сами

Используйте рекурсивную локальную функцию для основной логики, а лямбду — для встроенного преобразования LINQ, позволяя каждому средству выполнять наиболее подходящую для него задачу.

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        // Local function: recursive, named, reusable
        static int DigitCount(int n) => Math.Abs(n) < 10 ? 1 : 1 + DigitCount(n / 10);

        var nums = new List<int> { 5, 42, 1000, 7, 88 };
        // Lambda: concise inline projection
        var report = nums.Select(n => n + " has " + DigitCount(n) + " digits");
        foreach (var line in report) Console.WriteLine(line);
    }
}

Быстрая проверка

Сравните эти два конструкта.

Итоги

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

  • Локальные функции могут быть рекурсивными и обобщёнными, а также использовать out/ref.
  • При прямом вызове они не требуют выделения памяти под делегат и замыкание.
  • Лямбды наиболее кратки, когда используются как непосредственные аргументы методов, например LINQ.
  • Выбирайте вариант исходя из цели: именованная повторно используемая вспомогательная функция или короткое встроенное поведение.

Часто задаваемые вопросы

Урок «Локальные функции и лямбда-выражения» бесплатный?

Да — полный текст урока «Локальные функции и лямбда-выражения» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Локальные функции и лямбда-выражения»?

Выбирайте между локальными функциями и лямбда-выражениями. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Локальные функции и лямбда-выражения»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Объявление локальных функций
  2. Замыкания и захваченные переменные
  3. Статические локальные функции
  4. Локальные функции и лямбда-выражения
← Назад к C# Academy