Является ли <Collection>.Count дорогим для использования?
Я пишу метод кэширования, который выглядит примерно так:
while ( myHashSet.Count > MAX_ALLOWED_CACHE_MEMBERS )
{
EjectOldestItem( myHashSet );
}
Мой вопрос о том, как определяется Count
: это просто a private
или protected int
, или он вычисляется путем подсчета элементов каждый раз при его вызове?
Ответы
Ответ 1
Из http://msdn.microsoft.com/en-us/library/ms132433.aspx:
Получение значения этого свойства является операцией O (1).
Это гарантирует, что доступ к Count
не будет проходить по всей коллекции.
Изменить: как и многие другие плакаты, IEnumerable<...>.Count()
, как правило, не гарантируется O (1). Используйте с осторожностью!
IEnumerable<...>.Count()
- это метод расширения, определенный в System.Linq.Enumerable
. Текущая реализация делает явный тест, если подсчитанный IEnumerable<T>
действительно является экземпляром ICollection<T>
и использует, если это возможно, ICollection<T>.Count
. В противном случае он пересекает IEnumerable<T>
(возможно, делает ленивую оценку расширяемой) и подсчитывает элементы один за другим.
Однако я не нашел в документации, гарантировал ли он, что IEnumerable<...>.Count()
использует O (1), если это возможно, я только проверил реализацию в .NET 3.5 с Reflector.
Необходимое позднее добавление: многие популярные контейнеры не получены из Collection<T>
, но тем не менее их свойство Count
равно O (1) (то есть не будет перебирать всю коллекцию). Примерами являются HashSet<T>.Count
(это, скорее всего, то, о чем хотел спросить OP), Dictionary<K, V>.Count
, LinkedList<T>.Count
, List<T>.Count
, Queue<T>.Count
, Stack<T>.Count
и т.д.
Все эти коллекции реализуют ICollection<T>
или просто ICollection
, поэтому их Count
представляет собой реализацию ICollection<T>.Count
(или ICollection.Count
). Для реализации ICollection<T>.Count
не требуется выполнение операции O (1), но те, о которых говорилось выше, делают это в соответствии с документацией.
(Обратите внимание: некоторые контейнеры, например Queue<T>
, реализуют не общие ICollection
, но не ICollection<T>
, поэтому они "наследуют" свойство Count
только от ICollection
.)
Ответ 2
В вашем вопросе не указан конкретный класс Collection, поэтому...
Это зависит от класса Collection. ArrayList имеет внутреннюю переменную, которая отслеживает счет, как и List. Однако это специфичная реализация, и в зависимости от типа коллекции она теоретически может быть пересчитана при каждом вызове.
Ответ 3
Это внутреннее значение и не вычисляется. В документации указано, что получение значения является операцией O (1).
Ответ 4
Как отмечали другие, граф поддерживается при изменении коллекции. Это почти всегда относится к каждому типу коллекции в рамках. Это значительно отличается от использования метода расширения Count в IEnumerable, который будет перечислять коллекцию каждый раз.
Кроме того, с новыми классами коллекций свойство Count не является виртуальным, что означает, что дрожание может встроить вызов в счетчик доступа, что делает его практически таким же, как доступ к полю. Другими словами, очень быстро.
Ответ 5
В случае HashSet
это просто внутреннее поле int
и даже SortedSet
(двоичный древовидный набор для .net 4) имеет свой счет во внутреннем поле.
Ответ 6
Согласно Reflector, он реализован как
public int Count{ get; }
поэтому он определяется производным типом
Ответ 7
Просто быстро. Будьте уверены, что есть два способа подсчета коллекции в .NET 3.5 при использовании System.Linq. Для обычной коллекции первым выбором должно быть использование свойства Count, по причинам, уже описанным в других ответах.
Также доступен альтернативный метод с помощью метода расширения LINQ.Count(). Интригующая вещь о .Count() заключается в том, что ее можно вызывать на ЛЮБОЙ перечислимый, независимо от того, реализует ли класс класса ICollection или нет, или имеет свойство Count. Если вы когда-либо звоните .Count(), имейте в виду, что он будет выполнять итерацию по коллекции, чтобы динамически генерировать счет. Это обычно приводит к сложности O (n).
Единственная причина, по которой я хотел это отметить, - использовать IntelliSense, часто бывает легко случайно использовать расширение Count(), а не свойство Count.
Ответ 8
Это внутренний int
, который увеличивается при каждом добавлении нового элемента в коллекцию.