Лямбда-функция в C# это чуть больше, чем кусок кода. Компилятор переписывает ваш код, и если понять как именно, многое встаёт на своё место.
Простой случай
Когда лямбда не захватывает никаких переменных, компилятор просто превращает её в обычный метод:
public class LambdaDemo2
{
private System.Timers.Timer? _timer;
private void HiddenMethodForLambda(
object? sender, System.Timers.ElapsedEventArgs args)
{
Console.WriteLine("Выполнено");
}
public void InitTimer()
{
_timer = new System.Timers.Timer(1000);
_timer.Elapsed += HiddenMethodForLambda;
_timer.Enabled = true;
}
}
Тело лямбды перемещается в отдельный метод. Среда выполнения работает с ним как с обычным методом — никаких особых структур.
Когда лямбда захватывает переменную
Ситуация усложняется, если внутри лямбды используется локальная переменная из внешнего метода:
public void InitTimer()
{
int aVariable = 5;
_timer = new System.Timers.Timer(1000);
_timer.Elapsed += (sender, args) => Console.WriteLine(aVariable);
_timer.Enabled = true;
}
Здесь уже один метод не поможет: нужно где-то хранить
aVariable так, чтобы к ней имели доступ сразу два места — InitTimer и лямбда. В .NET для этого используют классы.Компилятор генерирует вспомогательный класс и переносит туда локальную переменную:
public class LambdaDemo4
{
private System.Timers.Timer? _timer;
private class HiddenClassForLambda
{
public int aVariable;
public void HiddenMethodForLambda(
object? sender, System.Timers.ElapsedEventArgs args)
{
Console.WriteLine(aVariable);
}
}
public void InitTimer()
{
var hiddenObject = new HiddenClassForLambda();
hiddenObject.aVariable = 5;
_timer = new System.Timers.Timer(1000);
_timer.Elapsed += hiddenObject.HiddenMethodForLambda;
_timer.Enabled = true;
}
}
Локальная переменная стала полем класса. Метод
InitTimer и лямбда теперь обращаются к одному объекту hiddenObject.Когда лямбда захватывает переменную, способ доступа к ней меняется. То, что выглядело как работа с локальной переменной, после компиляции становится обращением к полю объекта в куче. Если в одном методе объявить несколько лямбд, захватывающих общие переменные, компилятор поместит их всех в один класс — чтобы они могли использовать одни и те же поля.
Это объясняет, почему захват переменных в лямбдах влияет на выделение памяти и время жизни объектов: захваченная переменная живёт столько, сколько живёт объект-носитель, а не до конца метода.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминатор