Почему в Enumerable.Any() отдается приоритет свойству Count выше чем MoveNext()?
Почему в теле метода Enumerable.Any<TSource> сначала пытаются достать свойство Count (внутри метода TryGetNonEnumeratedCount) и если не получается, то возвращается MoveNext() который как раз возвращает нужное нам bool значение. Почему бы сразу не сделать условный return MoveNext()? Какие преимущества у такого подхода? В IL никакой разницы между вызовом get у свойства и вызова метода нет, оба дёргаются за счет callvirt
Ответы (1 шт):
Автор решения: aepot
→ Ссылка
Оптимизация потому что.
Первичная инициализация энумератора требует создания его экземпляра, а выдача Count не требует инициализации энумератора.
Код (GitHub):
public static bool Any<TSource>(this IEnumerable<TSource> source)
{
return TryGetNonEnumeratedCount(source, out int count) ? count != 0 : WithEnumerator(source);
static bool WithEnumerator(IEnumerable<TSource> source)
{
using IEnumerator<TSource> e = source.GetEnumerator(); // вот оно, создание экземпляра энумератора
return e.MoveNext();
}
}
public static bool TryGetNonEnumeratedCount<TSource>(this IEnumerable<TSource> source, out int count)
{
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (source is ICollection<TSource> collectionoft)
{
count = collectionoft.Count;
return true;
}
if (source is IIListProvider<TSource> listProv)
{
int c = listProv.GetCount(onlyIfCheap: true);
if (c >= 0)
{
count = c;
return true;
}
}
if (source is ICollection collection)
{
count = collection.Count;
return true;
}
count = 0;
return false;
}