LAMBDA捕获问题迭代器? [英] Lambda capture problem with iterators?
问题描述
道歉,如果这个问题已经被问过,但假设我们有这样的代码(我使用Mono 2.10.2运行它,并与的GMC编译
2.10.2.0)
Apologies if this question has been asked already, but suppose we have this code (I've run it with Mono 2.10.2 and compiled with gmcs
2.10.2.0):
using System;
public class App {
public static void Main(string[] args) {
Func<string> f = null;
var strs = new string[]{
"foo",
"bar",
"zar"
};
foreach (var str in strs) {
if ("foo".Equals(str))
f = () => str;
}
Console.WriteLine(f()); // [1]: Prints 'zar'
foreach (var str in strs) {
var localStr = str;
if ("foo".Equals(str))
f = () => localStr;
}
Console.WriteLine(f()); // [2]: Prints 'foo'
{ int i = 0;
for (string str; i < strs.Length; ++i) {
str = strs[i];
if ("foo".Equals(str))
f = () => str;
}}
Console.WriteLine(f()); // [3]: Prints 'zar'
}
}
据逻辑上似乎 [1]
打印相同的 [3]
。但说实话,我有点希望它打印相同的 [2]
。我莫名其妙地相信的实施[1]
将接近 [2]
。
It seems logical that [1]
print the same as [3]
. But to be honest, I somehow expected it to print the same as [2]
. I somehow believed the implementation of [1]
would be closer to [2]
.
问:任何人都可以请提供到它告诉究竟是如何 STR
变量(或者规范的引用即使迭代器)由拉姆达在捕捉[1]
。
Question: Could anyone please provide a reference to the specification where it tells exactly how the str
variable (or perhaps even the iterator) is captured by the lambda in [1]
.
我想我所寻找的是确切的实施的foreach
循环。
I guess what I am looking for is the exact implementation of the foreach
loop.
推荐答案
您问了参考说明书;相关位置是部分8.8.4,其中规定了foreach循环相当于:
You asked for a reference to the specification; the relevant location is section 8.8.4, which states that a "foreach" loop is equivalent to:
V v;
while (e.MoveNext()) {
v = (V)(T)e.Current;
embedded-statement
}
请注意,该值V之外声明而循环,因此,有一个单独的循环变量。然后由拉姆达关闭了。
Note that the value v is declared outside the while loop, and therefore there is a single loop variable. That is then closed over by the lambda.
因为这么多的人碰上这种问题C#设计和编译器团队改变了C#5有这些语义
while (e.MoveNext()) {
V v = (V)(T)e.Current;
embedded-statement
}
而后者则具有预期的行为 - 你每次收过不同的变量。从技术上讲这是一个重大更改,但谁取决于您所遇到的怪异行为的人数是希望非常小。
Which then has the expected behaviour -- you close over a different variable every time. Technically that is a breaking change, but the number of people who depend on the weird behaviour you are experiencing is hopefully very small.
注意,C#2,3和4,现在用在这方面的C#5不相容。还要注意,更改仅适用于的foreach
,而不是为
循环。
Be aware that C# 2, 3, and 4 are now incompatible with C# 5 in this regard. Also note that the change only applies to foreach
, not to for
loops.
请参阅的 http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/ 了解详情。
批评家abergmeier状态:
Commenter abergmeier states:
C#是具有这种唯一的语言奇怪的行为。
C# is the only language that has this strange behavior.
这种说法是错误的断然。考虑下面的JavaScript:
This statement is categorically false. Consider the following JavaScript:
var funcs = [];
var results = [];
for(prop in { a : 10, b : 20 })
{
funcs.push(function() { return prop; });
results.push(funcs[0]());
}
abergmeier,你会关心采取猜测,是什么内容结果
?
这篇关于LAMBDA捕获问题迭代器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!