下面的代码
int factor = 2;
Transformer sqr = x => x * factor;
Console.WriteLine(sqr(3)); // 6
factor = 4;
Console.WriteLine(sqr(3)); // 12
我认为lambda应该在编译时捕获因子,因此两个writeline的结果应该是相同的。
但是,当我运行时,我得到6和12,C#lambda也使用动态范围? 我认为lambda应该使用一种叫做“词法范围”的东西
答案 0 :(得分:4)
首先,您无法在编译时捕获任何内容。 lambda的环境只能在运行时捕获,因为这是它存在的唯一时间。
当一个变量被lambda捕获时,lambda实际上可以在整个生命周期内直接访问该变量; lambda(google“访问修改后的闭包”)可以看到外部值的变化,反之亦然。
如果你想要将lambda与外部干扰隔离开来,你必须使它捕获“外部”中没有人可以访问的东西 - 这意味着一个范围有变量的变量已经足够有限了。
考虑:
int factor = 2;
Func<int, Func<int, int>> generateTransformer = f => x => x * f;
Func<int, int> sqr = generateTransformer(factor);
Console.WriteLine(sqr(3)); // 6
factor = 4;
Console.WriteLine(sqr(3)); // 6
这里发生的是sqr
是调用generateTransformer
的结果,它正在f
的主体内捕获局部变量generateTransformer
的值。这个价值永远不会被任何人改变,因为generateTransformer
的身体以外的任何人都看不到它。致电generateTransformer
会复制factor
的当前值,并将该“冻结”副本提供给sqr
以供使用。
答案 1 :(得分:2)
它 捕获factor
。它将它捕获为隐藏闭包类的成员变量,以及lambda的方法。你最终会得到与
private class sqrClosure
{
public int factor;
public int srq(int x)
{
return x * factor;
}
}
...
var c = new sqrClosure();
c.factor = 2;
Console.Writeline(c.sqr(3));
c.factor = 4;
Console.Writeline(c.sqr(3));
答案 2 :(得分:1)
它捕获factor
,但它捕获变量而不是变量的值。
因此,当您更改变量,然后调用lambda时,它将获取捕获变量的当前值。