День двести третий. #ЗаметкиНаПолях
Захват переменных лямбда-выражениями
Внутри лямбда-выражения вы можете использовать любую переменную, которую вы могли бы использовать в обычном коде в данном месте. Это может быть статическое поле, поле экземпляра (если вы пишете лямбда-выражение внутри экземплярного метода), переменная this, параметры метода или локальные переменные. Все они называются захваченными переменными, потому что они объявленны вне непосредственного контекста лямбда-выражения. Для сравнения параметры лямбда-выражения или локальные переменные, объявленные внутри лямбда-выражения не являются захваченными переменными. В следующем примере показан захват различных переменных лямбда-выражением:
-
захватывается лямбда-выражением.
-
-
-
-
-
Важно понимать, что лямбда-выражение захватывает сами переменные, а не значения переменных в момент создания делегата. Если вы изменили какую-либо из захваченных переменных между временем создания делегата и его вызовом, лямбда-выражение «увидит» эти изменения. Аналогично, лямбда-выражение может изменить значение захваченных переменных. Более того, в этом случае каждый последующий вызов лямбда-выражения будет «видеть» изменения захваченных переменных, сделанные предыдущими вызовами.
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 3.
Захват переменных лямбда-выражениями
Внутри лямбда-выражения вы можете использовать любую переменную, которую вы могли бы использовать в обычном коде в данном месте. Это может быть статическое поле, поле экземпляра (если вы пишете лямбда-выражение внутри экземплярного метода), переменная this, параметры метода или локальные переменные. Все они называются захваченными переменными, потому что они объявленны вне непосредственного контекста лямбда-выражения. Для сравнения параметры лямбда-выражения или локальные переменные, объявленные внутри лямбда-выражения не являются захваченными переменными. В следующем примере показан захват различных переменных лямбда-выражением:
class CapturedVariablesDemo…
{
private string instanceField = "instance field";
public Action<string> CreateAction(string methodParameter)
{
string methodLocal = "method local";
string uncaptured = "uncaptured local";
Action<string> action = lambdaParameter =>
{
string lambdaLocal = "lambda local";
Console.WriteLine("Instance field: {0}", instanceField);
Console.WriteLine("Method parameter: {0}", methodParameter);
Console.WriteLine("Method local: {0}", methodLocal);
Console.WriteLine("Lambda parameter: {0}", lambdaParameter);
Console.WriteLine("Lambda local: {0}", lambdaLocal);
};
methodLocal = "modified method local";
return action;
}
}
var demo = new CapturedVariablesDemo();Вывод:
Action<string> action = demo.CreateAction("method argument");
action("lambda argument");
Instance field: instance fieldВ этом примере задействованы следующие переменные:
Method parameter: method argument
Method local: modified method local
Lambda parameter: lambda argument
Lambda local: lambda local
-
instanceField
- поле экземпляра класса CapturedVariablesDemo
,захватывается лямбда-выражением.
-
methodParameter
- параметр метода CreateAction
, захватывается лямбда-выражением.-
methodLocal
- локальная переменная метода CreateAction
, захватывается и изменяется лямбда-выражением.-
uncaptured
- локальная переменная метода CreateAction
, не используется лямбда-выражением, поэтому не захватывается им.-
lambdaParameter
- параметр лямбда-выражения, не является захваченной переменной.-
lambdaLocal
- локальная переменная в лямбда-выражении, не является захваченной переменной.Важно понимать, что лямбда-выражение захватывает сами переменные, а не значения переменных в момент создания делегата. Если вы изменили какую-либо из захваченных переменных между временем создания делегата и его вызовом, лямбда-выражение «увидит» эти изменения. Аналогично, лямбда-выражение может изменить значение захваченных переменных. Более того, в этом случае каждый последующий вызов лямбда-выражения будет «видеть» изменения захваченных переменных, сделанные предыдущими вызовами.
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 3.