我们对Code ReviewLINQ Enumerable进行了一些自省,并发现了不同的策略来迭代IEnumerable<TSource>以向我们提供有关它的一些信息。

任何

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;
 }

 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;
  }


计数

public static int Count<TSource>(this IEnumerable<TSource> source)
{
    if (source == null) throw Error.ArgumentNull("source");
    ICollection<TSource> collectionoft = source as ICollection<TSource>;
    if (collectionoft != null) return collectionoft.Count;
    ICollection collection = source as ICollection;
    if (collection != null) return collection.Count;
    int count = 0;
    using (IEnumerator<TSource> e = source.GetEnumerator()) {
        checked {
            while (e.MoveNext()) count++;
        }
    }
    return count;
}


单一或默认

public static TSource SingleOrDefault<TSource>(
    this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null) throw Error.ArgumentNull("source");
    if (predicate == null) throw Error.ArgumentNull("predicate");
    TSource result = default(TSource);
    long count = 0;
    foreach (TSource element in source) {
        if (predicate(element)) {
            result = element;
            checked { count++; }
        }
    }
    switch (count) {
        case 0: return default(TSource);
        case 1: return result;
    }
    throw Error.MoreThanOneMatch();
}




如您所见,使用了3种不同的策略。


任意:迭代枚举器,并提前退出
Count:迭代枚举数,除非ICollection调用Count
SingleOrDefault:对枚举数进行迭代,而无需提前退出


一些观察:


'Any()'也可以针对ICollection进行优化
'SingleOrDefault'也可以进行优化以提早退出
尽管有ICountOnlyCollection属性也具有“ Count”属性,但这些方法都不关心IReadOnlyCollection


问题:


每个策略的利弊是什么?
LINQ的实现是按原样执行的,有充分的理由吗?

最佳答案

好吧,前两种方法是不言自明的,不是吗?对它们进行了优化,以使其尽快停止,并检查类型是否具有Count属性以避免循环。

但是带有谓词的SingleOrDefault确实有一个奇怪的实现。它可以在第二个匹配项处停止,因为这样很明显必须抛出InvalidOperationException(与Single...相对的First...确保最多有1个项目)。但是,它会检查每个项目并计算匹配项。
version without predicate具有此优化。

所以问题是:到底是什么?看来is really a bug不会得到解决,因为它只是在错误情况下降低了性能。我不敢相信

顺便说一句,Enumerable.Single中存在相同的错误。

关于c# - LINQ可列举策略比较:Any,Count,SingleOrDefault,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57223288/

10-12 12:37
查看更多