Счетчик ArrayList против любого

Я смотрю на какой-то устаревший код. Класс использует ArrayList для хранения элементов. Элементы извлекаются из таблицы базы данных, и их может быть до 6 миллионов. Класс предоставляет метод ListCount для получения количества элементов в Arraylist.

Class Settings
{
    ArrayList settingsList ;
    public Settings()
    {
      settingsList = GetSettings();//Get the settings from the DB. Can also return null
    }

    public int ListCount
    {
        get
        {
           if (settingsList == null )
             return 0;
           else
             return settingsList.Count;
        }
    }
}

ListCount используется для проверки наличия элементов в списке. Мне интересно ввести в класс метод 'Any'.

public bool Any(Func<vpSettings, bool> predicate)
{
   return settingsList !=null && settingsList.Cast<vpSettings>().Any(predicate);
}

Вопрос в том, выполняет ли фреймворк какую-то оптимизацию и поддерживает ли количество элементов или выполняет итерацию по Arraylist для получения подсчета? Было бы целесообразно добавить метод «Любой», как указано выше.

Марк Гравел в следующем вопросе советует использовать Any для IEnumerable

Какой метод работает лучше: .Any() vs .Count() › 0 ?


person AlwaysAProgrammer    schedule 29.04.2014    source источник
comment
Можешь показать GetSettings? Например, IList и IDictionary происходят от ICollection. Это одно из преимуществ этого дополнительного уровня гибкости. Array должен иметь меньше накладных расходов и быть быстрее.   -  person Greg    schedule 30.04.2014
comment
@Greg.. GetSettings () делает кучу вещей и вызывает методы в других классах, чтобы в конечном итоге читать из БД. Честно говоря, код этого метода повсюду.   -  person AlwaysAProgrammer    schedule 30.04.2014


Ответы (4)


В справочном источнике .NET говорится, что ArrayList.Count возвращает кэшированная частная переменная.

Для полноты картины в источнике также указана реализация метод расширения Any() здесь. По сути, метод расширения выполняет нулевую проверку, а затем пытается получить первый элемент через перечислитель IEnumerable.

person Andrew Varnerin    schedule 29.04.2014
comment
Это одна из моих любимых вещей, появившихся в проекте Roslyn — если вы не видели ее раньше, есть также способ интегрировать ее с Visual Studio, чтобы вы могли проверять/пошагово выполнять код. Очень удобно для получения быстрых ответов (или выяснения структуры). Вот подробнее - person Andrew Varnerin; 30.04.2014
comment
@Yogendra Справочный источник .NET сам по себе не вышел из проекта Roslyn; он доступен с 2007 года. Однако недавно этот опыт был расширен в связи с Roslyn. См. также visualstudiomagazine.com/articles/2014/ 26/02/. - person phoog; 30.04.2014

ArrayList на самом деле реализует IList, который должен быть быстрее, чем .Any(). Причина в том, что он реализует Count Property, а не Count Method. Count Property должен выполнить быструю проверку, а затем выбрать нужное свойство.

Что похоже на:

ICollection<TSource> collection1 = source as ICollection<TSource>;

  if (collection1 != null)
    return collection1.Count;

  ICollection collection2 = source as ICollection;

  if (collection2 != null)
    return collection2.Count;
person Greg    schedule 29.04.2014

Марк Гравел советует использовать Any() вместо Count() (метод расширения), но не обязательно вместо Count (свойство).

Свойство Count всегда будет быстрее, потому что оно просто ищет целое число, хранящееся в куче. Использование linq требует (относительно) дорогого выделения объекта для создания IEnumerator, а также любых накладных расходов в MoveNext (которые, если список не пуст, без необходимости копирует значение первого члена ArrayList в свойство Current перед возвратом true) .

Теперь все это довольно тривиально для производительности, но код для этого более сложен, поэтому его следует использовать только в том случае, если есть убедительное преимущество в производительности. Поскольку на самом деле это тривиальное снижение производительности, мы должны выбрать более простой код. Поэтому я бы реализовал Any() как return Count > 0;.

Однако в вашем примере реализована параметризованная перегрузка Any. В этом случае ваше решение, делегирующее параметризованный метод расширения Any, кажется лучшим. Нет никакой связи между параметризованным методом расширения Any и свойством Count.

person phoog    schedule 29.04.2014
comment
В моем примере массив массивов уже заполнен. Таким образом, предикат будет выполнять фильтрацию в памяти. - person AlwaysAProgrammer; 30.04.2014
comment
@Йогендра, кажется, я понимаю. Меня немного смутил тот факт, что ваш первый пример касался свойства Count, а второй — отфильтрованного метода Any. Реализация этого, как вы делаете в своем примере, имеет то преимущество, что инкапсулирует вызов Cast, поддерживая принцип DRY (en.wikipedia.org/wiki/Don't_repeat_yourself). - person phoog; 30.04.2014

ArrayList реализует IList, поэтому у него есть свойство Count. Использование этого было бы быстрее, чем Any(), если все, что вам нужно, это проверить контейнер (не-)пустота.

person Marius Bancila    schedule 29.04.2014