以下代码的答案为 5
有人可以解释为什么会这样吗?如果您要将int d1 = x.Current
替换为d1 = x.Current
并在while循环上方声明d1
,答案将是 2 ,我理解为什么会这样,但我不会# 39;不知道为什么它会这样做。
IEnumerable<int> num = new []{10,11,12,13,14,15,16};
IEnumerable<int> div = new [] {2,3,5};
var lazy = Enumerable.Empty<int>();
var x = div.GetEnumerator();
while(x.MoveNext()){
int d1 = x.Current;
lazy = lazy.Concat(num.Where(s=>s % d1 == 0));
}
int count = lazy.Distinct().Count();
Console.WriteLine("{0}",count);
编辑:这是给你答案2的片段。
IEnumerable<int> num = new []{10,11,12,13,14,15,16};
IEnumerable<int> div = new [] {2,3,5};
var lazy = Enumerable.Empty<int>();
var x = div.GetEnumerator();
int d1;
while(x.MoveNext()){
d1 = x.Current;
lazy = lazy.Concat(num.Where(s=>s % d1 == 0));
}
int count = lazy.Distinct().Count();
Console.WriteLine("{0}",count);
答案 0 :(得分:4)
这是因为在lazy.Concat(num.Where(s=>s % d1 == 0))
中延迟执行lambda表达式。
当您在循环内声明变量时,匿名方法的每个实例都会获得自己的变量。但是当你在循环外部声明变量时,它们都共享相同的变量,当然,当最终在这里执行lambda表达式时,变量的值只有一个值(循环中指定的最终值):
int count = lazy.Distinct().Count();
故事的寓意:谨防使用捕获的变量。它们通常很难推理,所以应该小心使用它们。
答案 1 :(得分:4)
您可以通过检测代码来更深入地了解差异。 lambda表达式中的检测是提供关键洞察力的东西:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Baseline.");
Test1();
Console.WriteLine("Modified.");
Test2();
}
static void Test1()
{
IEnumerable<int> num = new[] { 10, 11, 12, 13, 14, 15, 16 };
IEnumerable<int> div = new[] { 2, 3, 5 };
var lazy = Enumerable.Empty<int>();
var x = div.GetEnumerator();
while (x.MoveNext())
{
int d1 = x.Current;
Console.WriteLine("d1 = " + d1);
lazy = lazy.Concat(num.Where(s => {bool result = s % d1 == 0; Console.WriteLine("s = " + s + ", d1 = " + d1); return result;}));
Console.WriteLine("lazy has " + lazy.Count());
}
Console.WriteLine("Evaluating lazy.Distinct().Count()");
int count = lazy.Distinct().Count();
Console.WriteLine("{0}", count);
}
static void Test2()
{
IEnumerable<int> num = new[] { 10, 11, 12, 13, 14, 15, 16 };
IEnumerable<int> div = new[] { 2, 3, 5 };
var lazy = Enumerable.Empty<int>();
var x = div.GetEnumerator();
int d1;
while (x.MoveNext())
{
d1 = x.Current;
Console.WriteLine("d1 = " + d1);
lazy = lazy.Concat(num.Where(s => {bool result = s % d1 == 0; Console.WriteLine("s = " + s + ", d1 = " + d1); return result;}));
Console.WriteLine("lazy has " + lazy.Count());
}
Console.WriteLine("Evaluating lazy.Distinct().Count()");
int count = lazy.Distinct().Count();
Console.WriteLine("{0}", count);
}
}
&#34;评估lazy.Distinct()。Count()&#34;如果打印出来,你会注意到两件可能让你感到惊讶的事情。
首先,该评估需要重新运行在循环中声明的lambda表达式。想到&#34;懒惰&#34;这很容易,但却是错误的。作为整数的集合。实际上它是一个用于创建整数集合的函数,因此计算不同的元素需要重新运行该函数。
其次,您会注意到两个评估之间的d1值不同。在第一种情况下,d1是2,而在第二种情况下,d1是5.原因是,正如Peter Duniho指出的那样,在循环外声明d1允许它保留循环结束时的值(所以你有5,div序列中的最后一个值),在循环中声明它需要重新计算它(所以你有2,div序列中的第一个元素)。