lambda表达式如何共享局部变量?

Sau*_*jan 3 c#

我正在阅读lambda表达式,我已经看过这个例子,

例1:

static Func<int> Natural()
{
    int seed = 0;
    return () => seed++; // Returns a closure
}

static void Main()
{
    Func<int> natural = Natural();
    Console.WriteLine (natural()); // output : 0
    Console.WriteLine (natural()); // output : 1
}
Run Code Online (Sandbox Code Playgroud)

例2:

static Func<int> Natural()
{
    return() => { int seed = 0; return seed++; };
}

static void Main()
{
    Func<int> natural = Natural();
    Console.WriteLine (natural()); // output : 0
    Console.WriteLine (natural()); // output : 0
}
Run Code Online (Sandbox Code Playgroud)

我无法理解为什么第一个示例输出是0和1.

SJu*_*n76 6

因为第二个example(int seed = 0)中的初始化代码是在每次调用时运行的.

在第一个示例中,seed是一个捕获的变量,它存在于方法之外,因为在调用之间只保留一个实例.

更新:回应David Amo的评论,解释.

选项1)

static Func<int> Natural()
{
   int seed = 0;
   return () => seed++; // Returns a closure
}
Run Code Online (Sandbox Code Playgroud)

选项2)

static Func<int> Natural()
{
  return() => { int seed = 0; return seed++; };
}
Run Code Online (Sandbox Code Playgroud)

选项3)

static Func<int> Natural()
{
   int seed = 0;
   return () => { seed = 0; return seed++;}; // Returns a closure
}
Run Code Online (Sandbox Code Playgroud)

选项3返回与选项2相同的值,但内部作为选项1使用.seed是内部定义的变量Natural,但由于它由委托捕获,因此在方法退出后继续存在.

您可以用来查看正在发生的事情的另一个测试是

static Func<int> Natural()
{
  int seed = 1;
  Func<int> returnValue = () => { return seed++; };
  seed = 2;
  return returnValue;
}
Run Code Online (Sandbox Code Playgroud)


Pav*_*ari 5

lambda 表达式可以引用定义它的方法的局部变量和参数(外部变量

\n\n

lambda 表达式引用的外部变量称为捕获变量。捕获变量的 lambda 表达式称为闭包。

\n\n

捕获的变量在实际调用委托时计算,而不是在捕获变量时计算:

\n\n
int factor = 2;\nFunc<int, int> multiplier = n => n * factor;\nfactor = 10;\nConsole.WriteLine (multiplier (3));           // 30\n
Run Code Online (Sandbox Code Playgroud)\n\n

Lambda 表达式本身可以更新捕获的变量:

\n\n
int seed = 0;\nFunc<int> natural = () => seed++;\nConsole.WriteLine (natural());           // 0\nConsole.WriteLine (natural());           // 1\nConsole.WriteLine (seed);                // 2\n
Run Code Online (Sandbox Code Playgroud)\n\n

捕获的变量的生命周期延长到委托的生命周期。在下面的示例中,当 Natural 完成执行时,局部变量种子通常会从作用域中消失。但由于种子已被捕获,因此它的生命周期自然会延长到捕获委托的生命周期:

\n\n
static Func<int> Natural()\n{\n  int seed = 0;\n  return () => seed++;      // Returns a closure\n}\n\nstatic void Main()\n{\n  Func<int> natural = Natural();\n  Console.WriteLine (natural());      // 0\n  Console.WriteLine (natural());      // 1\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在 lambda 表达式中实例化的局部变量在每次调用委托实例时都是唯一的。如果我们重构前面的示例以在 lambda 表达式中实例化种子,我们会得到不同的(在本例中是不希望的)结果:

\n\n
static Func<int> Natural()\n{\n  return() => { int seed = 0; return seed++; };\n}\n\nstatic void Main()\n{\n  Func<int> natural = Natural();\n  Console.WriteLine (natural());           // 0\n  Console.WriteLine (natural());           // 0\n}\n
Run Code Online (Sandbox Code Playgroud)\n