【发布时间】:2019-12-04 23:46:17
【问题描述】:
我们对Code Review 或LINQ 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;
}
SingleOrDefault
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 种不同的策略。
- Any:迭代枚举器,提前退出
- Count:迭代枚举器,除非ICollection,调用Count
- SingleOrDefault:迭代枚举器,不提前退出
一些观察:
- “Any()”也可以针对 ICollection 进行优化
- “SingleOrDefault”也可以进行优化以提前退出
- 这些方法都不关心 IReadOnlyCollection,即使它也有一个属性 'Count'
问题:
- 这些策略的优缺点是什么?
- LINQ 的实现是这样的吗?
【问题讨论】:
-
如果您通过
Any和predicate,您必须查看项目以确定您是否至少有一个匹配项,所以我看不出如何针对@987654329 进行优化@ 除非您只是在谈论使用for循环。无论如何,这对于 SO 来说太基于意见了。 -
@steve16351 但它可能会在看到第二个匹配项时立即退出并出现错误。
-
@juharr 你对 Any(predicate) 是正确的,我还将包括 Any(),它可以针对 ICollection 进行优化
-
您正在查看 .NET Framework 源代码。 .NET Core 有一些 .NET Framework 没有的优化。例如,
SingleOrDefault带有谓词 does 一旦找到第二个匹配项就会短路。 -
这不是一个急切与懒惰的问题。调用
GetEnumerator可能需要创建一个新对象,但我猜任何额外的开销都不足以证明尝试强制转换是合理的。
标签: c# linq optimization enumerable reference-source