【发布时间】:2014-04-07 15:47:53
【问题描述】:
考虑以下 C# 程序:
using System;
using System.Linq;
using System.Collections.Generic;
public class Test
{
static IEnumerable<Action> Get()
{
for (int i = 0; i < 2; i++)
{
int capture = i;
yield return () => Console.WriteLine(capture.ToString());
}
}
public static void Main(string[] args)
{
foreach (var a in Get()) a();
foreach (var a in Get().ToList()) a();
}
}
在 Mono 编译器下执行时(例如 Mono 2.10.2.0 - 粘贴到 here),它会写入以下输出:
0
1
1
1
这对我来说似乎完全不合逻辑。当直接迭代yield函数时,for循环的范围是“正确”(据我理解)使用的。但是当我首先将结果存储在列表中时,范围始终是最后一个操作?!
我可以假设这是 Mono 编译器中的一个错误,还是我遇到了 C# 的 lambda 和 yield-stuff 的神秘角落?
顺便说一句:当使用 Visual Studio 编译器(以及 MS.NET 或 mono 执行)时,结果是预期的 0 1 0 1
【问题讨论】:
-
看起来像一个错误。我可以理解为什么它会是一个错误。因为它在一个迭代器块中,
capture最终被提升到一个新类型的字段来表示迭代器。然后评估闭包之后,关闭对迭代器的隐式引用并访问它的capture字段。 MS 确保在迭代器块的转换之前而不是之后执行闭包转换,这就是它具有不同行为的原因。 -
是的,这是 Mono 中的一个错误。如果您愿意,请随时向 Mono 团队报告。
-
啊,非常感谢您的回答。同时,我使用 Mono 的最新 Beta 版进行了测试,它给出了与 MS 编译器相同的结果,所以我猜 Mono 团队已经遇到过这种情况 :)