Wykonywanie Skip (i podobnych funkcji, takich jak Take)
Właśnie obejrzałem kod źródłowySkip
/Take
metody rozszerzania .NET Framework (naIEnumerable<T>
type) i okazało się, że wewnętrzna implementacja działa zGetEnumerator
metoda:
// .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;
}
}
}
Przypuśćmy, że mamIEnumerable<T>
z 1000 elementów (typ bazowy toList<T>
). Co się stanie, jeśli robię listę. Pomiń (990). Weź (10)? Czy przejdzie przez 990 pierwszych elementów, zanim przejdzie do ostatniej dziesiątki? (tak to rozumiem). Jeśli tak, to nie rozumiem, dlaczego Microsoft nie wdrożyłSkip
taka metoda:
// 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;
}
}
}
}
W rzeczywistości robili to dlaCount
metoda na przykład ...
// .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;
}
Więc jaki jest powód?