IEnumerable - 非空集合如何同时为空?

时间:2010-09-02 05:41:37

标签: c# ienumerable

我无法弄清楚这一点。传递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运行程序),它说更多,它说,收集产生没有结果(或类似的,不是逐字引用)。

问题:

  1. 如何通过重新排序将非空集合变为空?
  2. 收集计数怎么可以&gt; 0,什么时候没有物品?
  3. 我在问,因为我想知道如何避免这种情况,但老实说,当我查看代码时,我似乎100%合法。

    技术背景

    • 它是纯粹的C#代码,没有asm内联,或类似的任何内容
    • 没有线程
    • 没有外部库,除了Where(来自Linq)这是我的所有代码

    编辑

    修改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我会说),其中一个条件是时间依赖的。因此,当收集评估被迫改变条件时,我实际上得到了另一个集合。

3 个答案:

答案 0 :(得分:3)

一种可能性是两次评估条件有效地改变了结果。

每次遍历p时,它都会重新评估数据,包括Where子句。因此,您只需填充一次pool,然后再打印p.Count()

如果没有关于GetEntireCollection做什么或Where条件是什么的更多信息,很难说明发生了什么......但这是一种可能的解释。如果您可以发布一个简短但完整的程序来证明问题,那将会有很大帮助。

答案 1 :(得分:1)

由于延迟执行,它是空的,大多数查询运算符都不执行 构造,但枚举时(换句话说,当调用MoveNext时) 枚举)。

因此,如果您将其更改为:

var c = b.Where(condition2).ToList(); 

然后打电话给Foo(c)它会起作用。

答案 2 :(得分:0)

我认为您展示的代码会多次调用GetEntireCollection

因此,这个方法可能会在连续调用时返回不同的结果。