Захват переменных лямбда-выражениями
Внутри лямбда-выражения вы можете использовать любую переменную, которую вы могли бы использовать в обычном коде в данном месте. Это может быть статическое поле, поле экземпляра (если вы пишете лямбда-выражение внутри экземплярного метода), переменная 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.