我一直在调试这个生产错误,我迫不及待地寻求帮助,对我来说也很有趣。
我简化了代码逻辑并为调试添加了一些打印输出:
int[] a = { 2,2,2 };
var b = a.Where(x => x==2);
for(int i = 0; i < 3; i++)
{
var c = b.Where(x => x==i);
Console.WriteLine("iter {0} before - B Count: {1}, C Count: {2}", i, b.Count(), c.Count());
if (c.Count() != b.Count())
b = b.Except(c);
Console.WriteLine("iter {0} after - B Count: {1}, C Count: {2}", i, b.Count(), c.Count());
}
Console.WriteLine("After Loop: B Count: {0}", b.Count());
有趣的是(奇怪地),输出是:
iter 0 before - B Count: 3, C Count: 0
iter 0 after - B Count: 1, C Count: 0
iter 1 before - B Count: 1, C Count: 0
iter 1 after - B Count: 1, C Count: 0
iter 2 before - B Count: 0, C Count: 0
iter 2 after - B Count: 0, C Count: 0
After Loop: B Count: 1
为什么b.Count() == 0
在&#34;之前2&#34;。唯一的事情发生在&#34; iter 1之后和iter 2之前&#34;是
var c = b.Where(x => x==i);
为什么这段代码会改变b?
为什么b.Count()
在循环结束后变回1?
非常感谢大家的帮助指导我解决这个问题,谢谢!
答案 0 :(得分:4)
由于linq的懒惰评估,每次调用Where
时都会执行Except
和Count()
次调用。这里需要注意的重要一点是,i
的值不会被记住,而是会将i
的当前值用于所有之前的Where
次调用。
为什么b.Count()== 0 at“iter 2 before”
此时,i
已增加到2
。当您调用count时,将使用此值评估整个linq查询,这意味着之前添加的“Except”调用已经删除了所有内容!
为什么b.Count()在循环结束后变回1?
当i
等于3时,循环结束。现在,当您评估整个linq查询时,.Where(x => x==i)
个调用都不会返回任何内容,这反过来意味着没有Except
调用将删除任何内容(重复项除外)。
答案 1 :(得分:3)
对于 1 :&#34;为什么此代码会改变b?&#34;
它没有。添加(在循环开始时,c
之前):
Console.WriteLine("iter {0} before anything - B Count: {1}", i, b.Count());
b
没有变化。
对于 2 :由于捕获的i
而导致 2 。改为:
for(int tmp = 0 ; tmp < 3 ; tmp++) {
int i = tmp;
// ...
}
然后再试一次。现在i
的范围在循环中,并相应地捕获(for
循环中的迭代器变量的范围在循环之外,复杂的原因;在foreach
循环中,迭代器变量的范围是在循环内部还是外部取决于您正在使用的C#版本。
答案 2 :(得分:1)
Except
就像它的SQL版本一样,它可以消除重复。因此,它的行为就像在列表中调用Distinct
一样。
所以当你第一次执行Except
if (c.Count() != b.Count()) // c.Count() == 0, b.Count() == 3
b = b.Except(c);
您只能获得b
的唯一元素,其中只有一个元素。
答案 3 :(得分:0)
Enumerable.Except
通过使用默认的相等比较器来比较值来产生两个序列的集合差异。集合不包含重复项。
这就是为什么序列在Except
之后只包含一个2。
int[] onlyOneTwo = new[]{ 2,2,2 }.Except(Enumerable.Empty<int>()).ToArray();
因此,除Except
blueUsers($db, $core, ...)
之外,空序列不会删除任何内容。