c# 在 Lambda 表达式中声明变量
Posted
技术标签:
【中文标题】c# 在 Lambda 表达式中声明变量【英文标题】:c# declaring variables inside Lambda expressions 【发布时间】:2013-05-24 00:07:57 【问题描述】:以下代码输出 33 而不是 012。我不明白为什么每次迭代都没有捕获新变量 loopScopedi 而不是捕获相同的变量。
Action[] actions = new Action[3];
for (int i = 0; i < 3; i++)
actions [i] = () => int loopScopedi = i; Console.Write (loopScopedi);;
foreach (Action a in actions) a(); // 333
但是,这段代码生成 012。两者有什么区别?
Action[] actions = new Action[3];
for (int i = 0; i < 3; i++)
int loopScopedi = i;
actions [i] = () => Console.Write (loopScopedi);
foreach (Action a in actions) a(); // 012
【问题讨论】:
啊,这是一个修改后的关闭问题 - 请参阅 ***.com/questions/235455/access-to-modified-closure 关闭问题:codethinked.com/c-closures-explained 例如。 .net = 4.5 中的行为不同 阅读 Eric Lippert blogs.msdn.com/b/ericlippert/archive/2009/11/16/… 和 blogs.msdn.com/b/ericlippert/archive/2009/11/12/… 的这两个条目 【参考方案1】:这称为“访问修改后的闭包”。基本上,只有一个 i
变量,所有三个 lambdas 都在引用它。最后,一个i
变量已递增到3
,因此所有三个操作都打印3
。 (请注意,lambda 中的 int loopScopedi = i
仅在您稍后调用 lambda 时运行。)
在第二个版本中,您将为每次迭代创建一个新的int loopScopedi
,并将其设置为i
的当前值,即0
和1
和2
,每次迭代。
您可以尝试想象内联 lambda,以更清楚地了解正在发生的事情:
foreach (Action a in actions)
int loopScopedi = i; // i == 3, since this is after the for loop
Console.Write(loopScopedi); // always outputs 3
对比:
foreach (Action a in actions)
// normally you could not refer to loopScopedi here, but the lambda lets you
// you have "captured" a reference to the loopScopedi variables in the lambda
// there are three loopScopedis that each saved a different value of i
// at the time that it was allocated
Console.Write(loopScopedi); // outputs 0, 1, 2
【讨论】:
【参考方案2】:在 lambda 中捕获的变量被提升到 lambda 和外部代码之间共享的类中。
在您的第一个示例中,i
被提升一次,并与 for()
和所有传递的 lambda 一起使用。当您到达 Console.WriteLine
时,i
已经从 for()
循环到达 3
。
在您的第二个示例中,每次循环运行都会提升一个新的loopScopedi
,因此它不受后续循环的影响。
【讨论】:
【参考方案3】:这是关于 C# 如何处理闭包的。在第一个示例中,不会正确捕获闭包,您最终将始终使用最后一个值;但在第二个示例中,您在占位符中捕获循环变量的当前值,然后使用该占位符;这提供了正确的解决方案。
C# 在 foreach 循环中捕获循环变量的方式与 C# 5.0 和以前版本中的 for 循环之间存在差异 - 这是一个重大变化。
我(几乎)有同样的问题,我知道了here。
【讨论】:
【参考方案4】:两者有什么区别?
范围不同。
在您的第一个循环中,您指的是在for
循环语句范围中定义的i
变量,而在第二个循环中您使用的是局部变量。 333 输出是由于您的第一个循环迭代 3 次,因此 i
变量最终增加到 3,然后当您调用操作时,它们都引用 same变量(i
)。
在第二个循环中,您使用一个新变量 for each Action
,所以您会得到 012。
【讨论】:
以上是关于c# 在 Lambda 表达式中声明变量的主要内容,如果未能解决你的问题,请参考以下文章