<Набор>.Count дорог для Использования?

Я пишу, что кэш - извлекает метод, который по существу похож на это:

while ( myHashSet.Count > MAX_ALLOWED_CACHE_MEMBERS )
{
    EjectOldestItem( myHashSet );
}

Мой вопрос о как Count определяется: это просто a private или protected int, или это вычисляется путем подсчета элементов каждым разом его названный?

23
задан Bob Kaufman 12 February 2013 в 22:35
поделиться

8 ответов

Из http : //msdn.microsoft.com/en-us/library/ms132433.aspx :

Получение значения этого свойства является операцией O (1).

Это гарантирует, что доступ к счетчику не будет повторяться по всей коллекции.


Изменить: как предлагали многие другие плакаты, IEnumerable <...>. Count () , однако не гарантированно будет O (1). Используйте с осторожностью!

IEnumerable <...>. Count () - это метод расширения, определенный в System.Linq.Enumerable . Текущая реализация выполняет явную проверку, действительно ли подсчитываемый IEnumerable является экземпляром ICollection , и использует ICollection .Count , если возможно. В противном случае он просматривает IEnumerable (возможно, расширяя ленивую оценку) и подсчитывает элементы один за другим.

Однако я не нашел в документации, гарантируется ли, что IEnumerable <...>. Count () использует O (1), если это возможно, я только проверил реализацию в .NET 3.5 с помощью Отражатель.


Необходимое позднее добавление: многие популярные контейнеры не являются производными от Collection , но, тем не менее, их свойство Count равно O (1) (то есть не повторяется вся коллекция).Примеры: HashSet .Count (это, скорее всего, то, о чем OP хотел спросить), Dictionary .Count , LinkedList .Count , List .Count , Queue .Count , Stack .Count и так далее.

Все эти коллекции реализуют ICollection или просто ICollection , поэтому их Count является реализацией ICollection .Count (или ICollection.Count ). Не требуется, чтобы реализация ICollection .Count была операцией O (1), но упомянутые выше, согласно документации, делают именно так.

(Примечание в сторону: некоторые контейнеры, например Queue , реализуют неуниверсальную ICollection , но не ICollection , поэтому они "наследовать" свойство Count только от ICollection .)

44
ответ дан 29 November 2019 в 00:50
поделиться

Это внутреннее значение, которое не вычисляется. В документации указано, что получение значения является операцией O (1).

7
ответ дан 29 November 2019 в 00:50
поделиться

Как отмечали другие , Счетчик сохраняется при изменении коллекции. Это почти всегда относится к каждому типу коллекции в структуре. Это значительно отличается от использования метода расширения Count в IEnumerable, который будет перечислять коллекцию каждый раз.

Кроме того, в более новых классах коллекций свойство Count не является виртуальным, что означает, что джиттер может встроить вызов метода доступа Count, что делает его практически таким же, как доступ к полю. Другими словами, очень быстро.

6
ответ дан 29 November 2019 в 00:50
поделиться

В случае HashSet это просто внутреннее поле int , и даже SortedSet (набор на основе двоичного дерева для .net 4) имеет счет в внутреннее поле.

4
ответ дан 29 November 2019 в 00:50
поделиться

Это внутренний int , который увеличивается каждый раз, когда в коллекцию добавляется новый элемент.

1
ответ дан 29 November 2019 в 00:50
поделиться

Просто небольшое примечание. Помните, что есть два способа подсчета коллекции в .NET 3.5 при использовании System.Linq. Для обычной коллекции первым выбором должно быть использование свойства Count по причинам, уже описанным в других ответах.

Также доступен альтернативный метод через метод расширения LINQ .Count (). Интересным в .Count () является то, что его можно вызывать для ЛЮБОГО перечислимого объекта, независимо от того, реализует ли базовый класс ICollection или нет, или имеет ли он свойство Count. Однако, если вы когда-нибудь вызовете .Count (), имейте в виду, что он БУДЕТ перебирать коллекцию, чтобы динамически генерировать счетчик. Обычно это приводит к сложности O (n).

Единственная причина, по которой я хотел это отметить, заключается в том, что при использовании IntelliSense часто легко случайно закончить использование расширения Count (), а не свойства Count.

2
ответ дан 29 November 2019 в 00:50
поделиться

В вашем вопросе не указан конкретный класс Collection, поэтому .. .

Это зависит от класса Collection. ArrayList имеет внутреннюю переменную, которая отслеживает счетчик, как и List. Однако это зависит от реализации и в зависимости от типа коллекции теоретически может пересчитываться при каждом вызове.

9
ответ дан 29 November 2019 в 00:50
поделиться

Согласно Reflector, он реализован как

public int Count{ get; }

, поэтому он определяется производным типом

3
ответ дан 29 November 2019 в 00:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: