以下在VS 2010中给出答案1,在VS 2012中给出2个答案。我个人认为它应该是2.我不确定这里发生了什么。
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
namespace _335ExamPreparation
{
public class Doubts
{
int[] nums = { 10, 11, 12, 13, 14, 15, 16 };
int[] divisors = { 7, 10 };
static void Main(string[] args)
{
Doubts d = new Doubts();
d.func();
}
public void func()
{
var m = Enumerable.Empty<int>();
foreach (int d in divisors)
{
m = m.Concat(nums.Where(s => (s % d == 0)));
}
int count = m.Distinct().Count();
Console.WriteLine(count);
}
}
}
感谢。
答案 0 :(得分:16)
您所看到的是foreach
的两种不同应用的结果。 VS 2012中的行为已更改。请参阅this article。
两者之间的差异涉及d
循环中foreach
变量的范围和生命周期。在VS 2012之前,只有一个d
变量,所以这意味着你要创建一个两个副本(s => (s % d == 0))
),它们都引用相同的 {{ 1}}。在完成循环评估之后,d
为10.当您通过调用d
执行查询时,两个闭包都会为.Distinct().Count()
看到值10。这就是VS 2010上的计数为1的原因。
VS 2012为每个迭代 1 生成一个不同的变量,因此每个闭包都会看到d
变量的不同的实例,对应于特定的迭代。
这大致是VS 2010生成的代码:
d
这大致是VS 2012产生的结果:
int d;
for (int _index = 0; _index < divisors.Length; ++_index) {
d = divisors[_index];
m = m.Concat(nums.Where(s => (s % d == 0)));
}
这两者之间的区别应该很明显。
如果你想获得相同的行为,无论哪个VS版本,那么总是复制你的迭代变量:
for (int _index = 0; _index < divisors.Length; ++_index) {
int d = divisors[_index];
m = m.Concat(nums.Where(s => (s % d == 0)));
}
1 从技术上讲,只有在闭包中引用迭代变量时。如果不是那么就没有必要复制,因为这只会影响闭包语义。