我无法弄清楚这一点。传递IEnumerable< T>的工作流程(T是我的班级,但这里不相关)基本上看起来像这样:
var a = GetEntireCollection(); // so I get IEnumerable<T>
...
var b = a.Where(condition1);
...
var c = b.Where(condition2);
...
所以我从集合中过滤掉了越来越多的项目,最后我打电话给:
if (z.IsEmpty())
throw new Exception();
Foo(z);
和Foo是
public void Foo(IEnumerable<T> p)
{
pool = p.OrderByDescending(it => it.MyProperty).ToList();
if (pool.IsEmpty())
throw new Exception(pool.Count().ToString() + ", " + p.Count().ToString());
...
我所做的就是订购。
现在,我的程序崩溃,异常 - 它说p有Count = 1,池有Count = 0.当我指出p并要求结果时(我使用Visual Studio运行程序),它说更多,它说,收集产生没有结果(或类似的,不是逐字引用)。
问题:
我在问,因为我想知道如何避免这种情况,但老实说,当我查看代码时,我似乎100%合法。
技术背景:
修改1
public static bool IsEmpty<T>(this IEnumerable<T> coll)
{
var iter = coll.GetEnumerator();
return !iter.MoveNext();
}
修改2
在我调用Foo(z)之前,我检查z是否为空,所以代码如下:
if (z.IsEmpty())
throw new Exception();
Foo(z);
正如乔恩所说(C#sharpshooting我会说),其中一个条件是时间依赖的。因此,当收集评估被迫改变条件时,我实际上得到了另一个集合。
答案 0 :(得分:3)
一种可能性是两次评估条件有效地改变了结果。
每次遍历p
时,它都会重新评估数据,包括Where
子句。因此,您只需填充一次pool
,然后再打印p.Count()
。
如果没有关于GetEntireCollection
做什么或Where
条件是什么的更多信息,很难说明发生了什么......但这是一种可能的解释。如果您可以发布一个简短但完整的程序来证明问题,那将会有很大帮助。
答案 1 :(得分:1)
由于延迟执行,它是空的,大多数查询运算符都不执行 构造,但枚举时(换句话说,当调用MoveNext时) 枚举)。
因此,如果您将其更改为:
var c = b.Where(condition2).ToList();
然后打电话给Foo(c)它会起作用。
答案 2 :(得分:0)
我认为您展示的代码会多次调用GetEntireCollection
。
因此,这个方法可能会在连续调用时返回不同的结果。