В С# при использовании List <T> полезно ли кэшировать свойство Count или свойство достаточно быстро?

Другими словами, какое из следующего было бы быстрее, если бы какой-либо?

List<MyClass> myList;
...
...
foreach (Whatever whatever in SomeOtherLongList)
{
  ...
  if (i < myList.Count)
  {
    ...
  }
}

или

List<MyClass> myList;
...
...
int listCount = myList.Count;
foreach (Whatever whatever in SomeOtherLongList)
{
  ...
  if (i < listCount)
  {
    ...
  }
}

Спасибо:)

Ответ 1

Count - это просто целое число. он не вычисляется, когда вы запрашиваете его значение. он "предварительно рассчитан", так что то же самое. вариант 1 более читаем:)

Ответ 2

Для List<T> нет необходимости кэшировать его, поскольку это просто свойство.

Однако метод расширения Count(), который может быть использован для любого IEnumerable, может быть очень дорогостоящим, поскольку для его подсчета может потребоваться перечислить всю последовательность (для списков он просто использует свойство, но все остальное перечисляется). Кроме того, если вам просто нужно знать, является ли count не нулем, предпочтительнее использовать метод расширения Any().

Ответ 3

Вы можете посмотреть через Reflector, чтобы посмотреть на реализацию Count:

public int Count
{
    get
    {
        return this._size;
    }
}

Как мы видим, Count - это просто свойство, возвращающее член _size, который всегда обновляется при добавлении/удалении элементов в/из списка:

public void Add(T item)
{
    if (this._size == this._items.Length)
    {
        this.EnsureCapacity(this._size + 1);
    }
    this._items[this._size++] = item;
    this._version++;
}

public void RemoveAt(int index)
{
    if (index >= this._size)
    {
        ThrowHelper.ThrowArgumentOutOfRangeException();
    }
    this._size--;
    if (index < this._size)
    {
        Array.Copy(this._items, index + 1, this._items, index, this._size - index);
    }
    this._items[this._size] = default(T);
    this._version++;
}

поэтому нет необходимости кэшировать свойство.

Ответ 4

Первый вариант более читабельный и лучший, там вы также not wasting the memory of int (listCount).

в обоих случаях не будет никакой разницы в производительности.

Count in List автоматически определяется одним, после создания списка

Ответ 5

Кэширование явно будет быстрее b/c, вы сохраняете вызовы функций, чтобы получить счет, даже если это просто переменная.

Поскольку значение может меняться между итерациями цикла, компилятор не избавится от этих вызовов функций, поскольку это может изменить семантику кода.