Свойство Count против метода Count ()?


85

Работая с коллекцией, у меня есть два способа получить количество объектов; Count(свойство) и Count()(метод). Кто-нибудь знает, в чем основные отличия?

Возможно, я ошибаюсь, но я всегда использую это Countсвойство в любых условных операторах, потому что предполагаю, что Count()метод выполняет какой-то запрос к коллекции, где as Countдолжно быть уже назначено до того, как я «получил». Но это предположение - я не знаю, повлияет ли на производительность, если я ошибусь.

РЕДАКТИРОВАТЬ: Тогда из любопытства вызовет Count()исключение, если коллекция равна нулю? Потому что я почти уверен, что Countсвойство просто возвращает 0.


7
Оба вызовут исключение для пустых коллекций, потому что оба пытаются применить .оператор к чему-то, что имеет значение NULL.
AaronLS

Ответы:


110

Декомпиляция источника для Count()метода расширения показывает, что он проверяет, является ли объект ICollection(общим или другим), и если да, просто возвращает базовое Countсвойство:

Итак, если ваш код обращается Countвместо вызова Count(), вы можете обойти проверку типов - теоретический выигрыш в производительности, но я сомневаюсь, что он будет заметным!

// System.Linq.Enumerable
public static int Count<TSource>(this IEnumerable<TSource> source)
{
    checked
    {
        if (source == null)
        {
            throw Error.ArgumentNull("source");
        }
        ICollection<TSource> collection = source as ICollection<TSource>;
        if (collection != null)
        {
            return collection.Count;
        }
        ICollection collection2 = source as ICollection;
        if (collection2 != null)
        {
            return collection2.Count;
        }
        int num = 0;
        using (IEnumerator<TSource> enumerator = source.GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                num++;
            }
        }
        return num;
    }
}

10
+1 за инициативу перепроектировать это, очень полезно.
Polynomial

7
Однако имейте в виду, что в 3.5 Count()не проверяется неуниверсальный ICollectionинтерфейс. Это было добавлено только в .NET 4. Обе версии 3.5 и 4 проверяют наличие универсального ICollection<T>интерфейса.
thecoop 01

2
счетчик вызовов в последовательности без элементов вызовет исключение. Но Count () будет работать нормально.
Amesh

33

Производительность - лишь одна из причин выбрать то или иное. Выбор .Count()означает, что ваш код будет более общим. У меня были случаи, когда я реорганизовал некоторый код, который больше не создавал коллекцию, а вместо этого делал что-то более общее, например IEnumerable, но в результате другой код ломался, потому что он зависел, .Countи мне приходилось менять его на .Count(). Если бы я решил использовать его .Count()везде, код, вероятно, можно было бы использовать повторно и поддерживать. Обычно лучше всего использовать более общие интерфейсы, если вам это удается. Под более общим я подразумеваю более простой интерфейс, который реализуется большим количеством типов и, таким образом, обеспечивает большую совместимость кода.

Я не говорю, .Count()что лучше, я просто говорю, что есть другие соображения, которые больше касаются повторного использования кода, который вы пишете.


2
+1 Ценное дополнение к обсуждению. Некоторый код, который я поддерживаю, просто сломался, потому что свойство .Count не пережило обновление версии HtmlAgilityPack.
Дэн Соловей

1
Это может быть обоюдоострый меч. Что, если однажды кто-то попытается изменить IEnumerable, чтобы он стал настоящим генератором. Глядя на кодовую базу, я вижу много мест, где .Count () предполагает, что перечисляемое может повторяться несколько раз
bashrc

@bashrc Верно. Я думаю, что если мы рассматриваем изменение кода разработчика по сравнению с изменением кода фреймворка, более вероятно, что код разработчика изменится. Если бы такое изменение было сделано во фреймворке, это бы сломало многое. Традиционно в этих случаях они вводят новые коллекции / интерфейсы, чтобы разработчики могли мигрировать по своему желанию.
AaronLS

20

.Count()Метод может быть достаточно умны, или знать о типе в вопросе, и если да, то он может использовать основную .Countсобственность.

Опять же, может и нет.

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

Если .Count()метод не знает о коллекции, он выполнит перечисление по ней, что будет операцией O (n).


3
Использование Countсвойства могло бы быть лучше, но использование Count()метода ICollection<T>.Countкак бы задокументировано здесь: msdn.microsoft.com/en-us/library/bb338038(v=vs.110).aspx
nawfal

Не знаю, откуда вы знаете почти все.
snr

5

Count()Метод - это метод расширения, который выполняет итерацию по каждому элементу IEnumerable<>и возвращает количество имеющихся элементов. Если экземпляр IEnumerableдействительно является a List<>, значит, он оптимизирован для возврата Countсвойства вместо повторения всех элементов.


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

3

Count()существует как метод расширения от LINQ - Countэто свойство Lists, реальных объектов коллекции .NET.

Таким образом, Count()почти всегда будет медленнее, поскольку он будет перечислять объект коллекции / запроса. В списке, очереди, стеке и т. Д. Используйте Count. Или для массива - Length.


3

Краткая версия: если у вас есть выбор между Countсвойством и Count()методом, всегда выбирайте свойство.

Разница в основном заключается в эффективности работы. Все коллекции BCL, которые предоставляют Countсвойство, делают это способом O (1). Однако этот Count()метод может стоить и часто будет стоить O (N). Есть несколько проверок, чтобы попытаться получить O (1) для некоторых реализаций, но это никоим образом не гарантируется.


Я думаю , что этот ответ является более разумным для подсчета использования имущества
AT

3

Если есть свойство Countили Length, вы всегда должны предпочесть его Count()методу, который обычно выполняет итерацию всей коллекции для подсчета количества элементов внутри. Исключениями могут быть Count()случаи, когда метод относится к источнику LINQ to SQL или LINQ to Entities, например, и в этом случае он будет выполнять запрос подсчета для источника данных. Даже тогда, если есть Countсобственность, вы бы предпочли ее, поскольку у нее, вероятно, меньше работы.


3

Это Count()метод LINQ, который работает с любыми IEnumerable<>. Вы ожидаете, что Count()метод будет перебирать всю коллекцию, чтобы найти счетчик, но я считаю, что код LINQ действительно имеет некоторые оптимизации, чтобы определить, существует ли свойство Count, и если да, используйте его.

Так что они оба должны делать почти одинаковые вещи. Свойство Count, вероятно, немного лучше, поскольку здесь не требуется проверка типа.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.