Властивість Count проти методу Count ()?


85

Працюючи з колекцією, я маю два способи отримати кількість об’єктів; Count(властивість) та Count()(метод). Хтось знає, які ключові відмінності?

Можливо, я помиляюся, але я завжди використовую Countвластивість у будь-яких умовних операторах, оскільки я припускаю, що Count()метод виконує якийсь запит щодо колекції, де, як Countуже було призначено до мого "отримання". Але це припущення - я не знаю, чи це вплине на продуктивність, якщо я помиляюся.

РЕДАГУВАТИ: Тоді, з цікавості, Count()викине виняток, якщо колекція нульова? Тому що я майже впевнений, що Countвластивість просто повертає 0.


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

Відповіді:


109

Декомпіляція джерела для 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 за те, що ви взяли на себе ініціативу щодо зворотного проектування цього, дуже корисно.
Поліном

7
Однак майте на увазі, що у версії 3.5 Count()не перевіряється не-загальний ICollectionінтерфейс. Це було додано лише у .NET 4. І 3.5, і 4 перевіряють загальний ICollection<T>інтерфейс.
thecoop

2
виклик count на послідовність без елементів призведе до винятку. Але 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

Я не знаю, звідки ти знаєш майже все.
снр

5

Count()method - це метод розширення, який повторює кожен елемент an 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) для деяких реалізацій, але це аж ніяк не гарантується.


Я думаю, що ця відповідь є більш розумною для використання властивості count
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.