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

85

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

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

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

d219
источник
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()что лучше, я просто говорю, что есть другие соображения, которые больше касаются повторного использования кода, который вы пишете.

AaronLS
источник
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, вероятно, немного лучше, поскольку здесь не требуется проверка типа.

Дилан Смит
источник