可以';我不明白这个IEnumerable为什么会给出这个答案
本文关键字:为什么 答案 IEnumerable 明白 可以 | 更新日期: 2023-09-27 18:29:26
以下代码的答案是5
有人能解释一下为什么会这样吗?如果将int d1 = x.Current
替换为d1 = x.Current
,并在while循环上方声明d1
,答案将是2,我理解为什么是这样,但我不知道为什么是5。
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);
(Peter把我打得落花流水,但当他的答案出现时,我已经完成了一半,所以我无论如何都会发布它。)
您可以通过检测代码来深入了解差异。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);
}
}
打印"Evaluating.Distinct().Count()"之后,您会注意到两件可能会让您感到惊讶的事情。
首先,该求值需要重新运行在循环中声明的lambda表达式。将"懒惰"视为整数的集合很容易,但这是错误的。事实上,它是一个用于创建整数集合的函数,因此计算不同元素需要重新运行该函数。
其次,您会注意到d1的值在两个评估之间是不同的。在第一种情况下,d1是2,在第二种情况下d1是5。正如Peter Duniho所指出的,原因是在循环外声明d1允许它保留循环结束时的值(因此有5,div序列中的最后一个值),在循环内声明它需要重新计算它(因此有2,div序列的第一个元素)。
这是因为延迟执行lazy.Concat(num.Where(s=>s % d1 == 0))
中的lambda表达式。
当您在循环中声明变量时,匿名方法的每个实例都会获得自己的变量。但是,当您在循环外声明变量时,它们都共享同一个变量,当然,当lambda表达式最终在这里执行时,该变量的值只有一个值(循环中分配的最终值):
int count = lazy.Distinct().Count();
这个故事的寓意是:小心使用捕捉到的变量。它们通常很难推理,所以应该小心使用。