我刚刚看了一下源代码Skip
/Take
.NET Framework 的扩展方法(在IEnumerable<T>
类型)并发现内部实现正在与GetEnumerator
method:
// .NET framework
public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> source, int count)
{
if (source == null) throw Error.ArgumentNull("source");
return SkipIterator<TSource>(source, count);
}
static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
while (count > 0 && e.MoveNext()) count--;
if (count <= 0)
{
while (e.MoveNext()) yield return e.Current;
}
}
}
假设我有一个IEnumerable<T>
有 1000 个元素(底层类型是List<T>
)。如果我执行 list.Skip(990).Take(10) 会发生什么?它会在获取最后十个元素之前迭代前 990 个元素吗? (我是这样理解的)。如果是的话,那么我不明白为什么微软没有实施Skip
像这样的方法:
// Not tested... just to show the idea
public static IEnumerable<T> Skip<T>(this IEnumerable<T> source, int count)
{
if (source is IList<T>)
{
IList<T> list = (IList<T>)source;
for (int i = count; i < list.Count; i++)
{
yield return list[i];
}
}
else if (source is IList)
{
IList list = (IList)source;
for (int i = count; i < list.Count; i++)
{
yield return (T)list[i];
}
}
else
{
// .NET framework
using (IEnumerator<T> e = source.GetEnumerator())
{
while (count > 0 && e.MoveNext()) count--;
if (count <= 0)
{
while (e.MoveNext()) yield return e.Current;
}
}
}
}
事实上,他们这样做是为了Count
方法例如...
// .NET Framework...
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;
}
那么原因是什么呢?
在 Jon Skeet 的优秀教程中重新实现Linq https://codeblog.jonskeet.uk/2011/01/02/reimplementing-linq-to-objects-part-23-take-skip-takewhile-skipwhile/,他(简短地)讨论了这个问题:
尽管这些操作中的大多数都无法进行合理的优化,但它
当源实现 IList 时,优化 Skip 是有意义的。
我们可以跳过跳过,可以这么说,直接进入
适当的索引。这不会发现来源所在的情况
在迭代之间进行修改,这可能是它不是的原因之一
据我所知,已在框架中实现。
这似乎是推迟优化的合理理由,但我同意,对于特定情况,如果您可以保证您的源代码不能/不会被修改,那么进行优化可能是值得的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)