Linq任何()副作用

时间:2015-07-22 07:42:29

标签: c# linq

如果反射器是正确的(我倾向于相信它),这就是Any()的实现:

public static bool Any<TSource>(this IEnumerable<TSource> source) {
        if (source == null) throw Error.ArgumentNull("source");
        using (IEnumerator<TSource> e = source.GetEnumerator()) {
            if (e.MoveNext()) return true;
        }
        return false;
    }

根据我的理解,MoveNext()将基础枚举器移动一个位置,因此多次调用Any()会对&#34;收缩&#34;产生不利影响。集合。

我尝试使用List<>重现这一点,但我无法做到这一点,但是,我无法找出List<>做出不同的解决此问题的方法

验证List<T>的简单示例适用于多个Any()调用:

var meh = new List<string> {"1", "2"};
var enumerable = meh.AsEnumerable();
bool any = enumerable.Any(); //true
any = enumerable.Any(); //true
any = enumerable.Any(); //true but isn't it meant to have "moved" the enumerator by two positions already?
any = enumerable.Any(); //true

所以我的问题是:

  1. 我是否理解Any()确实对Enumerable
  2. 确实有副作用
  3. 如果是这样,List<>如何绕过它?
  4. 很抱歉,如果提前这是一个愚蠢的问题。只是我发现非常有趣的东西。

1 个答案:

答案 0 :(得分:6)

由于using语句处理了枚举器,所以它始终从头开始。枚举器也始终从source.GetEnumerator()创建,不会重复使用。实际上这是.NET源代码,你可以看到here

Any的其他重载也是如此:

public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
    if (source == null) throw Error.ArgumentNull("source");
    if (predicate == null) throw Error.ArgumentNull("predicate");
    foreach (TSource element in source) {
        if (predicate(element)) return true;
    }
    return false;
}

它枚举序列直到谓词匹配,然后它将被处理掉。

此方法也不使用延迟执行(它缺少yield关键字)。因此,它总是立即执行。

相关问题