作者:陈尧倩682 | 来源:互联网 | 2023-02-01 14:55
为什么以下代码打印11次?
int i = 10;
Action fn1 = () => Console.WriteLine(i);
i = 11;
Action fn2 = () => Console.WriteLine(i);
fn1();
fn2();
产出11 11
根据这篇文章中的答案 - 如何告诉lambda函数捕获副本而不是C#中的引用? - 将lambda转换为具有捕获变量副本的类.如果是这样的话我的例子不应该打印10和11吗?
现在,当lambda通过引用捕获时它如何影响捕获的变量的生命周期.例如,假设上面的代码片段在函数中,并且Actions的范围对于变量是全局的,如下所示:
class Test
{
Action _fn1;
Action _fn2;
void setActions()
{
int i = 10;
_fn1 = () => Console.WriteLine(i);
i = 11;
_fn2 = () => Console.WriteLine(i);
}
static void Main()
{
setActions();
_fn1();
_fn2();
}
}
在这种情况下,当调用操作时,变量i不会超出范围吗?那么,这些动作是否留下悬挂指针的参考?
1> Jon Skeet..:
如果是这样的话我的例子不应该打印10和11吗?
不,因为你只有一个变量 - fn1
捕获变量,而不是它的当前值.所以像这样的方法:
static void Foo()
{
int i = 10;
Action fn1 = () => Console.WriteLine(i);
i = 11;
Action fn2 = () => Console.WriteLine(i);
fn1();
fn2();
}
翻译成这样:
class Test
{
class MainVariableHolder
{
public int i;
public void fn1() => Console.WriteLine(i);
public void fn2() => Console.WriteLine(i);
}
void Foo()
{
var holder = new MainVariableHolder();
holder.i = 10;
Action fn1 = holder.fn1;
holder.i = 11;
Action fn2 = holder.fn2;
fn1();
fn2();
}
}
这也回答了你的第二点:变量被"提升"到一个类中,因此只要委托是活着的,它的生命周期就会有效地扩展.